patterngoModerate
Buffered vs unbuffered channels: semantics and use cases
Viewed 0 times
buffered channelunbuffered channelchannel capacitygoroutine synchronizationchannel queuechannel backpressure
Error Messages
Problem
Choosing the wrong channel buffer size causes unexpected blocking (unbuffered where you needed async) or hidden backpressure bugs (buffered with wrong capacity).
Solution
Understand the guarantees each provides:
Rule of thumb:
// Unbuffered: send blocks until receiver is ready
// Guarantees synchronization — sender KNOWS receiver got the value
ch := make(chan int)
go func() { ch <- 42 }() // blocks until main receives
fmt.Println(<-ch)
// Buffered: send only blocks when buffer is full
// Decouples producer and consumer; provides a queue
ch := make(chan Job, 100)
for _, j := range jobs {
ch <- j // blocks only when buffer full
}
close(ch)
for j := range ch {
process(j)
}Rule of thumb:
- Use unbuffered for synchronization/handoff
- Use buffered when producer and consumer run at different rates and you have a known bound
Why
Unbuffered channels synchronize goroutines — the send completes only when a receiver is waiting. Buffered channels act as queues, decoupling timing but not eliminating backpressure when the buffer fills.
Gotchas
- A buffered channel with a large buffer can mask goroutine leaks by absorbing all sends even when consumers are dead
- Ranging over an unclosed channel blocks forever — always close the channel when no more values will be sent
- Sending to a closed channel panics; receiving from a closed channel returns the zero value immediately
Revisions (0)
No revisions yet.