Channel Patterns
Overview
Channels enable safe communication between goroutines. This chapter covers essential channel patterns.
Channel Directions
chan T // Bidirectional
chan<- T // Send-only
<-chan T // Receive-only
func producer(out chan<- int) { }
func consumer(in <-chan int) { }Buffered vs Unbuffered
// Unbuffered: send blocks until receive
ch := make(chan int)
// Buffered: send blocks when full
ch := make(chan int, 10)Closing Channels
close(ch)
// Check if closed
v, ok := <-ch
if !ok {
// Channel closed
}
// Range over channel
for v := range ch {
// Receives until closed
}Select
select {
case v := <-ch1:
fmt.Println("from ch1:", v)
case v := <-ch2:
fmt.Println("from ch2:", v)
case ch3 <- x:
fmt.Println("sent to ch3")
default:
fmt.Println("no channel ready")
}Timeout Pattern
select {
case result := <-ch:
fmt.Println(result)
case <-time.After(1 * time.Second):
fmt.Println("timeout")
}Done Channel
done := make(chan struct{})
go func() {
// Work...
close(done) // Signal completion
}()
<-done // Wait for signalFan-Out/Fan-In
// Fan-out: multiple goroutines read from one channel
func fanOut(in <-chan int, workers int) []<-chan int {
outs := make([]<-chan int, workers)
for i := 0; i < workers; i++ {
outs[i] = worker(in)
}
return outs
}
// Fan-in: merge multiple channels into one
func fanIn(ins ...<-chan int) <-chan int {
out := make(chan int)
var wg sync.WaitGroup
for _, in := range ins {
wg.Add(1)
go func(ch <-chan int) {
defer wg.Done()
for v := range ch {
out <- v
}
}(in)
}
go func() {
wg.Wait()
close(out)
}()
return out
}Summary
| Pattern | Use Case |
|---|---|
| Unbuffered | Synchronization |
| Buffered | Decouple speed |
| Select | Multiple channels |
| Done channel | Cancellation signal |
| Fan-out/in | Parallel processing |