How to Fix Go Select Statement Random Case Selection Confusion
In this tutorial, you'll learn about How to Fix Go Select Statement Random Case Selection Confusion. We cover key concepts, practical examples, and best practices.
Go's select statement chooses a random ready case when multiple cases are ready simultaneously. This behavior causes confusion when developers expect deterministic ordering or fair scheduling across channel operations.
Quick Fix
Wrong
ch1 := make(chan string, 1)
ch2 := make(chan string, 1)
ch1 <- "msg1"
ch2 <- "msg2"
select {
case msg := <-ch1:
fmt.Println("Got from ch1:", msg)
case msg := <-ch2:
fmt.Println("Got from ch2:", msg)
}
The output is non-deterministic. Either channel can be selected randomly when both are ready.
Right
ch1 := make(chan string, 1)
ch2 := make(chan string, 1)
ch1 <- "msg1"
ch2 <- "msg2"
// Read from ch1 first
msg1 := <-ch1
fmt.Println("Got from ch1:", msg1)
// Then read from ch2
msg2 := <-ch2
fmt.Println("Got from ch2:", msg2)
Got from ch1: msg1
Got from ch2: msg2
Fix for priority
for i := 0; i < 3; i++ {
select {
case msg := <-highPriority:
fmt.Println("High:", msg)
case msg := <-lowPriority:
// Check if high priority is also ready
select {
case highMsg := <-highPriority:
fmt.Println("High:", highMsg)
fmt.Println("Low:", msg)
default:
fmt.Println("Low:", msg)
}
}
}
Fix for fairness
func fairSelect(ch1, ch2 <-chan string) {
for ch1 != nil || ch2 != nil {
select {
case msg, ok := <-ch1:
if !ok { ch1 = nil; continue }
fmt.Println("Got from ch1:", msg)
case msg, ok := <-ch2:
if !ok { ch2 = nil; continue }
fmt.Println("Got from ch2:", msg)
}
}
}
Prevention
- Do not rely on case ordering in
selectstatements. - Use direct channel reads for deterministic ordering.
- Implement priority queues with separate select statements.
- Handle closed channels by setting them to nil in select loops.
- Document that select chooses randomly among ready cases.
DodaTech Tools
Doda Browser's Go concurrency analyzer visualizes select statement behavior and potential starvation. DodaZIP archives goroutine traces for debugging. Durga Antivirus Pro detects infinite select loops without nil channel handling.
Common Mistakes with select case random
- Mixing let bindings with <- bindings in do notation, producing type errors
- Overlapping type class instances that cause GHC to reject the program with ambiguous dispatch errors
- Non-exhaustive pattern matches that compile with warnings then crash at runtime
These mistakes appear frequently in real-world GO code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.
Practice Exercise
Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.
This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro