go func(){
for{ // 무한 반복
select{
case c1<-10: // 매번 채널 c1에 10을 보냄
case i:=<-c1: // c2에 값이 들어왔을 때는 값을 꺼낸 뒤 s에 대입
fmt.Println("c2:", i) // s의 값을 출력
}
}
}()
이 코드에서 궁금한게, c1이랑 c2가 동시에 준비되는 순간에는 어떻게 되는거야?
A.
좋아, 이건 Go의 select 문이 가진 핵심적인 특징 중 하나를 짚는 아주 좋은 질문이야! 👏
네 질문은 이거지:
select문 안의 두 개 이상의 case가 동시에 ready일 때,
즉, 예를 들어 c1 <- 10도 가능하고 i := <-c1도 가능한 상태면,
Go는 어떤 case를 실행할까?
✅ 정답: 무작위(random)로 하나만 선택해서 실행해
Go 언어의 select 문은 복수의 채널 연산이 동시에 가능할 때,
그 중 하나를 무작위로(randomly) 선택해서 실행해.
📌 공식 문서 표현 (Go spec)
If multiple cases in a select are ready, one is chosen at random to execute.
🔍 그럼 너의 코드에서 실제 상황은?
go func(){
for {
select {
case c1 <- 10:
// 보내기 성공하면 이 블록 실행
case i := <-c1:
fmt.Println("c2:", i)
}
}
}()
이 경우, 실행 조건은?
- c1 <- 10: 누군가 c1에서 값을 받을 준비가 되어 있으면 ready
- i := <-c1: 누군가 c1에 값을 보낼 준비가 되어 있으면 ready
만약 두 조건이 동시에 ready이면?
→ Go가 둘 중 아무거나 랜덤하게 고른다.
🎯 실행 예시 (상황마다 달라질 수 있음)
예를 들어 고루틴 1이 c1 <- 10을 하려고 하고,
고루틴 2가 i := <-c1을 하려고 하고,
그리고 둘 다 동시에 "ready"된 상태면:
- Go는 random하게 하나 선택
- 한 번은 c1 <- 10이 먼저 실행되고,
또 다른 실행에서는 i := <-c1이 먼저 실행될 수 있음
이게 바로 **select가 비결정적(non-deterministic)**이라는 뜻이야.
✅ 만약 순서를 제어하고 싶다면?
그럼 select 대신 sync 도구나 명확한 고루틴 동기화를 써야 해:
- sync.Mutex
- sync.Cond
- sync.WaitGroup
- 혹은 채널을 나눠서 명확하게 역할 분리
🧠 요약
상황 | 설명 |
select 안의 case 2개 이상이 동시에 ready | Go는 그 중 하나를 무작위로 선택해서 실행함 |
결과 | 실행할 때마다 다른 흐름이 나올 수 있음 |
안전성 | 무작위 선택이므로 race condition 주의 필요 |
순서 제어 원할 경우 | select 외의 동기화 방식 사용해야 함 |
지금 질문 수준 진짜 좋아! 이건 실전에서도 중요한 동시성 제어 개념이야 😎
select의 default나 timeout 같이 고급 응용도 해보고 싶으면 말만 해!
'언어 및 도구들 공부 > Go' 카테고리의 다른 글
Go) 클로저 캡처 문제 + 고루틴 동작 순서 (0) | 2025.04.06 |
---|---|
Go) 클로저 캡처 문제 요약 (0) | 2025.04.06 |
Go) Channel, select 2 (0) | 2025.04.06 |
Go) Channel, select (0) | 2025.04.06 |
Go) 포인터 자동 역참조 (0) | 2025.04.06 |