Go Concurrency Patterns
Production patterns for Go concurrency including goroutines, channels, synchronization primitives, and context management.
When to Use This Skill
- Building concurrent Go applications
- Implementing worker pools and pipelines
- Managing goroutine lifecycles
- Using channels for communication
- Debugging race conditions
- Implementing graceful shutdown
Core Concepts
Primitives
Patterns
The Go Concurrency Mantra
Don't communicate by sharing memory;
share memory by communicating.
Quick Reference
Spawning a Goroutine
go func() {
// Do work concurrently
}()
Creating a Channel
ch := make(chan int) // Unbuffered
ch := make(chan int, 10) // Buffered
Waiting for Goroutines
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
// Work
}()
wg.Wait()
Context Cancellation
ctx, cancel := context.WithCancel(context.Background())
go func() {
<-ctx.Done()
// Cleanup
}()
cancel() // Signal shutdown
Race Detection
# Run tests with race detector
go test -race ./...
# Build with race detector
go build -race .
Best Practices
- Do: Use context for cancellation
- Do: Close channels from sender side only
- Do: Use errgroup for concurrent operations
- Do: Buffer channels when you know the count
- Don't: Leak goroutines - always have exit path
- Don't: Close channels from receiver
- Don't: Use shared memory unless necessary
- Don't: Ignore context cancellation
Resources