Concurrency Patterns
Common Channel Patterns
Channels enable powerful concurrency patterns in Go:
graph TD
A[Fan-Out] --> B[Worker Pool]
B --> C[Select Pattern]
C --> D[Pipeline]
1. Fan-Out Pattern
Distribute work across multiple goroutines:
func fanOutExample() {
jobs := make(chan int, 100)
results := make(chan int, 100)
// Create worker goroutines
for w := 1; w <= 3; w++ {
go func(id int) {
for job := range jobs {
results <- processJob(job)
}
}(w)
}
// Send jobs
for j := 1; j <= 50; j++ {
jobs <- j
}
close(jobs)
}
2. Worker Pool Pattern
Manage a fixed number of concurrent workers:
func workerPoolExample() {
const numJobs = 50
const numWorkers = 5
jobs := make(chan int, numJobs)
results := make(chan int, numJobs)
// Create worker pool
for w := 1; w <= numWorkers; w++ {
go worker(w, jobs, results)
}
// Send jobs
for j := 1; j <= numJobs; j++ {
jobs <- j
}
close(jobs)
}
3. Select Pattern
Handle multiple channel operations:
func selectPatternExample() {
ch1 := make(chan string)
ch2 := make(chan string)
go func() {
for {
select {
case msg1 := <-ch1:
fmt.Println("Received from ch1:", msg1)
case msg2 := <-ch2:
fmt.Println("Received from ch2:", msg2)
case <-time.After(time.Second):
fmt.Println("Timeout")
}
}
}()
}
4. Pipeline Pattern
Process data through multiple stages:
func pipelineExample() {
// Stage 1: Generate numbers
numbers := generateNumbers()
// Stage 2: Square numbers
squared := squareNumbers(numbers)
// Stage 3: Filter even numbers
filtered := filterEvenNumbers(squared)
}
Concurrency Pattern Comparison
Pattern |
Use Case |
Complexity |
Scalability |
Fan-Out |
Distribute work |
Medium |
High |
Worker Pool |
Limit concurrent tasks |
Medium |
Medium |
Select |
Handle multiple channels |
Low |
Low |
Pipeline |
Data transformation |
High |
High |
Error Handling in Concurrent Patterns
func robustConcurrentPattern() {
errChan := make(chan error, 10)
go func() {
defer close(errChan)
// Perform concurrent operations
if err != nil {
errChan <- err
}
}()
// Collect and handle errors
for err := range errChan {
log.Println("Concurrent error:", err)
}
}
Best Practices
- Use buffered channels to prevent goroutine leaks
- Always close channels when done
- Implement proper error handling
- Limit the number of goroutines
By mastering these concurrency patterns, developers can create efficient and scalable applications in their LabEx Go projects.