What does this select print, and where does the break go?
Question 497MediumGo 1.22 to 1.25
a := make(chan int, 1)
b := make(chan int, 1)
a <- 1
b <- 2
select {
case v := <-a:
fmt.Println("a", v)
case v := <-b:
fmt.Println("b", v)
}
ticker := time.NewTicker(10 * time.Millisecond)
defer ticker.Stop()
done := time.After(50 * time.Millisecond)
for {
select {
case <-ticker.C:
fmt.Println("tick")
case <-done:
fmt.Println("done")
break // BUG: only exits the select
}
}
The first select prints either a 1 or b 2. When several cases are ready, Go picks one uniformly at random. Source order gives no priority, which prevents starvation. If you need priority, check the high-priority channel in its own non-blocking select first.
In the second part, break inside select (or switch) ends only the select. The for loop keeps going, prints "tick" forever, and never leaves after "done". Fix it with a label, or return:
loop:
for {
select {
case <-ticker.C:
fmt.Println("tick")
case <-done:
fmt.Println("done")
break loop
}
}More on Tricky Output & Code-Review Puzzles
- Q495Find the two WaitGroup bugs.
- Q496Why does this loop spin at 100% CPU after one channel closes?
- Q498What does each channel operation do on nil, open, and closed channels?
- Q499Which of these deadlock, and why does Go detect some deadlocks but not others?
- Q500Is msg guaranteed to print "hello"? Compare unbuffered and buffered channels.
- Q501Code review: why does this timeout wrapper leak goroutines?