프로그래밍백엔드 개발자

Go에서 select 메커니즘이 어떻게 작동하는지 설명하세요. 개발자들이 이를 사용할 때 어떤 일반적인 실수를 범하나요?

Hintsage AI 어시스턴트로 면접 통과

답변

select는 여러 채널에서의 데이터 수신 또는 종료를 기다릴 수 있는 Go의 강력한 구조입니다. 여러 케이스 중 하나가 준비되면 해당 블록이 실행되고, 나머지는 현재 반복에서 무시됩니다.

ch1 := make(chan int) ch2 := make(chan string) go func() { ch1 <- 42 }() go func() { ch2 <- "hello" }() select { case i := <-ch1: fmt.Println("ch1에서 수신됨:", i) case s := <-ch2: fmt.Println("ch2에서 수신됨:", s) default: fmt.Println("통신 없음") }

세부 사항:

  1. select 내 모든 연산은 채널이어야 하며, 그렇지 않으면 컴파일러가 오류를 발생시킵니다.
  2. 여러 케이스가 동시에 준비되면 하나의 케이스가 임의로 선택됩니다.
  3. Default 블록은 실행을 차단하지 않을 수 있습니다.

함정 질문

select 내 채널이 어느 것도 읽기/쓰기 준비가 되어 있지 않고 default 블록이 없는 경우 어떻게 될까요?

답변: Select는 채널 중 하나라도 작업을 수행할 준비가 될 때까지 차단됩니다.

세부 사항에 대한 무지로 인한 실제 오류 사례


이야기

개발자는 채널을 종료하는 기능을 select를 통해 default 블록 없이 구현했으며, 함수가 "제어를 넘길 것"이라 믿었습니다. 채널은 비어 있었고, 함수는 select에서 영원히 차단되어 마이크로서비스의 데이터 흐름이 정지했습니다.


이야기

여러 채널과 함께 select를 사용하면서 일부 goroutine에서 채널이 닫힐 때 catch되지 않은 패닉이 발생하여 메모리 누수 및 오류가 발생했습니다. 채널 종료를 확인하는 로직(ok 변수를 통한 체크)이 구현되지 않았습니다.


이야기

한 프로젝트에서 개발자들은 차단을 방지하기 위해 select에 default 블록을 추가했지만, 이는 busy loop를 초래했습니다. select가 반복적으로 실행되어 default가 즉시 작동하고 CPU 사용률이 100%에 도달했습니다. 이는 채널로부터 이벤트를 기다리기보다는 적극적으로 CPU를 소모하게 만드는 결과였습니다.