Buffered channels
Use buffering to encode known queueing or semaphore capacity, not to silence blocking you do not understand.
Canonical guidance
- use buffering when capacity has real semantics
- keep backpressure behavior understandable
- prefer unbuffered channels when synchronization is the point
Use when
- bounded work queues
- semaphore-like throttling
- absorbing short producer-consumer bursts
Avoid
- choosing capacity by superstition
- increasing the buffer until flaky tests stop failing
- assuming buffering makes leaks or deadlocks impossible
Preferred pattern
sem := make(chan struct{}, 8)
sem <- struct{}{}
Anti-pattern
- adding a buffer just because the sender should “probably not block”
Explanation: This anti-pattern is tempting because blocking feels scary, but unexplained buffering often hides a design bug instead of fixing it.
Why
- buffer size is part of the concurrency design, not a cosmetic tuning knob
Related pages
Sources
- The Go Programming Language Specification - Go Team
- Effective Go - Go Team