Go channels primer
Channels are Go's typed conduits for passing values between goroutines. They synchronize execution, communicate state, and replace the need for explicit locks in most pipeline workloads. This recipe walks through three patterns you will reach for every day.
1.Unbuffered vs buffered
An unbuffered channel forces sender and receiver to rendezvous: the send blocks until someone reads. A buffered channel decouples them up to its capacity, letting the producer run ahead until the buffer is full. Pick unbuffered when ordering matters and buffered when throughput does.
ch := make(chan int) // unbuffered: hand-off
buf := make(chan int, 16) // buffered: queue up to 16
go func() { ch <- 42 }() // blocks until received
v := <-ch // receives 422.Close to signal done
Closing a channel broadcasts "no more values" to every receiver. Ranging over a closed channel drains buffered values then exits cleanly. Only the sender should close, and only once — closing twice or sending to a closed channel panics.
jobs := make(chan int, 3)
go func() {
defer close(jobs)
for i := 0; i < 3; i++ { jobs <- i }
}()
for j := range jobs { fmt.Println(j) }3.Select for multiplexing
select waits on multiple channel operations and runs the first one ready. Combine it with time.After for timeouts or a default branch for non-blocking checks.
select {
case v := <-results:
handle(v)
case <-time.After(2 * time.Second):
return errors.New("timeout")
case <-ctx.Done():
return ctx.Err()
}