intermediate
Step 10 of 15
Channels and Select
Go Programming
Channels and Select
Channels are Go's primary mechanism for communication between goroutines. They provide a typed conduit through which you can send and receive values, enabling safe data sharing without locks. The select statement lets you wait on multiple channel operations simultaneously. Together, goroutines and channels implement Communicating Sequential Processes (CSP), a concurrency model that makes complex concurrent programs easier to reason about and less prone to bugs like deadlocks and race conditions.
Channel Basics
package main
import "fmt"
func main() {
// Unbuffered channel
ch := make(chan string)
go func() {
ch <- "Hello from goroutine!"
}()
msg := <-ch
fmt.Println(msg)
// Buffered channel
jobs := make(chan int, 5)
for i := 1; i <= 5; i++ {
jobs <- i
}
close(jobs)
for job := range jobs {
fmt.Println("Processing job", job)
}
}
// Worker pool pattern
func workerPool(numWorkers int, jobs <-chan int, results chan<- int) {
var wg sync.WaitGroup
for i := 0; i < numWorkers; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for job := range jobs {
results <- job * 2
}
}()
}
wg.Wait()
close(results)
}
Select Statement
// Select waits on multiple channels
select {
case msg := <-ch1:
fmt.Println("From ch1:", msg)
case msg := <-ch2:
fmt.Println("From ch2:", msg)
case <-time.After(5 * time.Second):
fmt.Println("Timeout!")
}
Pro tip: Always close channels from the sender side, never the receiver. Userangeto receive all values from a channel until it is closed. Useselectwithtime.After()to implement timeouts and prevent goroutines from blocking forever.
Key Takeaways
- Channels provide typed, safe communication between goroutines.
- Unbuffered channels synchronize sender and receiver; buffered channels allow asynchronous sends up to capacity.
- Use
selectto wait on multiple channels simultaneously. - Close channels from the sender; use
rangeto iterate until closed. - The worker pool pattern with channels is Go's standard approach to parallel processing.