select Flashcards
(11 cards)
Basic select
Syntax:
select { case msg := <-ch1: fmt.Println(msg) case ch2 <- data: fmt.Println("sent") }
Behavior:
* Blocks until one case can proceed
* Random selection if multiple cases ready
Non-Blocking select
Using default:
select { case val := <-ch: fmt.Println(val) default: fmt.Println("no value ready") }
Use Case: Poll channels without blocking
Timeout Pattern
With time.After:
select { case res := <-longOperation(): fmt.Println(res) case <-time.After(1 * time.Second): fmt.Println("timeout!") }
Key Point: Creates a temporary channel
Empty select
Blocks forever:
select {} // Equivalent to: for {}
Use Case: Prevent main() from exiting (rare)
Priority Selection
Immediate vs Fallback:
select { case job := <-priorityQueue: process(job) default: select { case job := <-normalQueue: process(job) case <-time.After(10 * time.Millisecond): fmt.Println("idle") } }
Combined with for
Continuous Monitoring:
~~~
for {
select {
case msg := <-msgCh:
handle(msg)
case <-stopCh:
return // Exit loop
}
}```
nil Channels
Behavior:
* Sends/receives on nil channels never execute
* Useful for disabling cases dynamically:
var dataCh chan Data // nil initially select { case data := <-dataCh: // Skipped process(data) case <-time.After(1 * time.Second): fmt.Println("no data channel") }
Multiple Actions
Single Case:
select { case val := <-ch: fmt.Println(val) fallthrough // Rarely used! case <-time.After(0): fmt.Println("always runs after first case") }
Common Pitfalls
❌ Forgetting default → deadlock risk
❌ Unbalanced channel operations → leaks
❌ Ignoring ok when checking closed channels
Real-World Patterns
- Fan-in:
select { case v := <-source1: out <- v case v := <-source2: out <- v }
- Graceful Shutdown:
select { case <-workDone: fmt.Println("completed") case <-ctx.Done(): fmt.Println("cancelled") }
Golden Rules
- select is Go’s switch for channels
- Always handle all possible cases
- Use timeouts to prevent deadlocks
- nil channels are useful for dynamic control