How do you implement a priority select in Go?
Question 191HardGo 1.22 to 1.25
Go has no built-in priority. The usual pattern is a non-blocking check of the high-priority channel first, followed by a blocking select over everything:
for {
// 1. Give ctx strict priority.
select {
case <-ctx.Done():
return ctx.Err()
default:
}
// 2. Block on all.
select {
case <-ctx.Done():
return ctx.Err()
case v := <-high:
handle(v)
case v := <-low:
// Before handling low, drain any pending high-priority work.
for drained := false; !drained; {
select {
case h := <-high:
handle(h)
default:
drained = true
}
}
handle(v)
}
}
Nuance to mention: priority is inherently best-effort in a concurrent system. A high-priority value can arrive a nanosecond after your check. The pattern reduces how often the wrong case wins, but it can't make it impossible. If ordering really matters, merge everything into a single channel with typed messages, or use a real priority queue guarded by a mutex and sync.Cond/signal channel.
More on Channels & select
- Q189How do you safely close a channel that might be closed by multiple goroutines?
- Q190How does
selectchoose among multiple ready cases? Is it fair? - Q192Why is a nil channel useful in a
select? Show an example. - Q193What does this print? (select with a closed channel and a nil channel)
- Q194What causes "fatal error: all goroutines are asleep - deadlock!" and when does Go fail to detect a deadlock?
- Q195What does this program do? (unbuffered send in main)