🔥 Default Selection
강의 목차
Go의 select
문은 여러 개의 채널에서 동시에 데이터를 기다리거나 보낼 수 있게 해줍니다. 하지만 만약 select
에서 기다리는 채널 중 어떤 채널도 준비되지 않았다면 어떻게 될까요? 이런 경우에는 default
케이스가 실행됩니다.
default
케이스는 select
에서 다른 케이스가 준비되지 않았을 때 실행되는 일종의 "백업 플랜"과 같습니다. 이를 활용하면 채널에서 값 받기를 시도할 때 블로킹 없이 바로 결과를 얻을 수 있습니다.
예를 들어, 다음과 같이 default
케이스를 사용할 수 있습니다:
select { case i := <-c: // c에서 값을 받아 i에 저장 default: // c에서 값 받기를 시도했지만 블로킹되므로 default 케이스 실행 }
go
위 코드에서는 채널 c
에서 값을 받으려고 시도합니다. 만약 c
에 값이 준비되어 있다면 그 값을 i
에 저장하고, 그렇지 않다면 default
케이스를 실행하여 블로킹 없이 바로 다음 코드로 넘어갑니다.
default
케이스의 활용 예시를 보다 자세히 알아보기 위해 다음 코드를 살펴봅시다:
package main import ( "fmt" "time" ) func main() { tick := time.Tick(100 * time.Millisecond) boom := time.After(500 * time.Millisecond) for { select { case <-tick: fmt.Println("tick.") case <-boom: fmt.Println("BOOM!") return default: fmt.Println(" .") time.Sleep(50 * time.Millisecond) } } }
go
이 코드는 다음과 같이 동작합니다:
tick
과boom
이라는 두 개의 채널을 생성합니다.tick
은 100ms마다 값을 만들어내는 채널입니다.boom
은 500ms 후에 값을 만들어내는 채널입니다.
- 무한 루프를 시작합니다.
- 루프 내에서
select
를 사용하여tick
,boom
, 그리고default
케이스를 기다립니다.tick
에서 값을 받으면 "tick."을 출력합니다.boom
에서 값을 받으면 "BOOM!"을 출력하고 프로그램을 종료합니다.tick
과boom
모두 값이 없다면default
케이스를 실행하여 " ."을 출력하고 50ms 동안 대기합니다.
- 2번으로 돌아가 루프를 계속 반복합니다.
이 코드를 실행하면 다음과 같은 출력 결과를 얻을 수 있습니다:
. . tick. . . tick. . . tick. . . tick. . . tick. BOOM!
text
초기에는 tick
과 boom
모두 값이 없으므로 default
케이스가 실행되어 " ."이 출력됩니다. 100ms마다 tick
에서 값을 받아 "tick."을 출력하고, 500ms가 지나면 boom
에서 값을 받아 "BOOM!"을 출력한 후 프로그램이 종료됩니다.
이렇게 default
케이스를 사용하면 select
에서 기다리는 채널들이 모두 블로킹되는 상황에서도 계속 진행할 수 있습니다. 상황에 따라 적절히 활용한다면 더욱 유연하고 능동적인 프로그램을 작성할 수 있겠죠? 예를 들어 GUI 시스템의 이벤트 루프를 간단하게 시뮬레이션 할 수 있습니다.
GUI 시스템의 이벤트 루프 구현
Go 채널과 select
를 활용하면 GUI 시스템의 이벤트 루프를 간결하고 효과적으로 구현할 수 있습니다. 다음은 간단한 예시 코드입니다:
package main import ( "fmt" ) func main() { // 이벤트 채널 생성 renderCh := make(chan string) systemNotificationCh := make(chan string) // 이벤트 발생 시뮬레이션 (goroutine) go func() { renderCh <- "Render Requested" systemNotificationCh <- "System Notification Received" }() // 이벤트 루프 for { select { case event := <-renderCh: fmt.Println("Render Event:", event) case event := <-systemNotificationCh: fmt.Println("System Notification Event:", event) default: // 이벤트가 없을 때 다른 작업 수행 가능 fmt.Println("No events, doing other work...") } } }
go
위 코드는 다음과 같이 동작합니다:
renderCh
와systemNotificationCh
라는 두 개의 이벤트 채널을 생성합니다.- 고루틴에서 이벤트 발생을 시뮬레이션합니다.
renderCh
에 "Render Requested" 이벤트를 보냅니다.systemNotificationCh
에 "System Notification Received" 이벤트를 보냅니다.
- 이벤트 루프를 시작합니다.
select
를 사용하여renderCh
,systemNotificationCh
, 그리고default
케이스를 기다립니다.renderCh
나systemNotificationCh
에서 이벤트를 받으면 해당 이벤트를 출력합니다.- 이벤트가 없다면
default
케이스를 실행하여 다른 작업을 수행할 수 있습니다.
- 이벤트 루프는 계속 반복되며, 이벤트 채널에서 이벤트를 기다립니다.
이런 식으로 Go 채널과 select
를 사용하면 GUI 시스템의 이벤트 루프를 간단하고 직관적으로 구현할 수 있습니다. 실제 GUI 라이브러리에서는 좀 더 복잡한 방식으로 구현되겠지만, 기본 개념은 유사합니다.