Channels
Use channels to communicate ownership and coordination, not as a default replacement for all synchronization.
Canonical guidance
- use channels for communication and coordination between goroutines
- prefer simple ownership transfer over shared mutable state
- choose buffering deliberately; do not use it to hide design problems
- close channels from the sending side when no more values will arrive
Use when
- pipelines
- worker coordination
- signaling completion or cancellation
Avoid
- using channels when a mutex around shared state is simpler
- closing channels from the receiver side
- multiple senders racing to close the same channel
Preferred pattern
out := make(chan Item)
go func() {
defer close(out)
for _, item := range items {
out <- item
}
}()
Anti-pattern
- channel graphs so complex that ownership and shutdown become unclear
Explanation: This anti-pattern is tempting because channels feel idiomatic, but overly complex channel graphs often hide ownership and shutdown mistakes.
Why
- channels are excellent when they model dataflow or coordination
- they are poor when used as decorative complexity around ordinary state access
Related pages
Sources
- Effective Go - Go Team
- Go Concurrency Patterns: Pipelines and cancellation - Sameer Ajmani
- The Go Programming Language Specification - Go Team