Concurrency Patterns
Common Concurrency Patterns in Go
Go provides powerful mechanisms for implementing concurrent programming patterns that help solve complex synchronization and communication challenges.
Worker Pool Pattern
Efficiently manage a group of goroutines processing tasks:
func workerPool(jobs <-chan int, results chan<- int) {
for job := range jobs {
results <- processJob(job)
}
}
func main() {
jobs := make(chan int, 100)
results := make(chan int, 100)
// Create worker pool
for w := 1; w <= 3; w++ {
go workerPool(jobs, results)
}
// Send jobs
for j := 1; j <= 5; j++ {
jobs <- j
}
close(jobs)
// Collect results
for a := 1; a <= 5; a++ {
<-results
}
}
Concurrency Patterns Visualization
graph TD
A[Job Queue] -->|Distribute| B[Worker 1]
A -->|Tasks| C[Worker 2]
A -->|Concurrently| D[Worker 3]
B --> E[Result Channel]
C --> E
D --> E
Pattern Types
Pattern |
Description |
Use Case |
Worker Pool |
Distribute tasks across multiple workers |
Parallel processing |
Fan-Out/Fan-In |
Multiple goroutines producing, single goroutine consuming |
Data aggregation |
Pipeline |
Process data through multiple stages |
Stream processing |
Fan-Out/Fan-In Pattern
Distribute work across multiple goroutines and aggregate results:
func fanOutFanIn(input <-chan int) <-chan int {
numWorkers := 3
outputs := make([]<-chan int, numWorkers)
// Fan-out
for i := 0; i < numWorkers; i++ {
outputs[i] = processData(input)
}
// Fan-in
return merge(outputs...)
}
func merge(channels ...<-chan int) <-chan int {
var wg sync.WaitGroup
mergedCh := make(chan int)
output := func(c <-chan int) {
defer wg.Done()
for n := range c {
mergedCh <- n
}
}
wg.Add(len(channels))
for _, ch := range channels {
go output(ch)
}
go func() {
wg.Wait()
close(mergedCh)
}()
return mergedCh
}
Pipeline Pattern
Create data processing pipelines:
func pipeline() <-chan int {
numbers := generateNumbers()
squared := squareNumbers(numbers)
return filterEven(squared)
}
func generateNumbers() <-chan int {
out := make(chan int)
go func() {
for i := 1; i <= 10; i++ {
out <- i
}
close(out)
}()
return out
}
Concurrency Pattern Best Practices
- Use channels for communication
- Avoid sharing memory
- Design for cancellation
- Implement proper error handling
Advanced Synchronization Considerations
graph TD
A[Concurrent Design] --> B[Communication]
A --> C[Minimal Shared State]
A --> D[Error Handling]
A --> E[Resource Management]
At LabEx, we recommend practicing these patterns to master Go's concurrent programming capabilities.