Concurrent Design Patterns
In addition to the basic tools for synchronizing Goroutines, Go also provides several concurrent design patterns that can be used to build more complex concurrent applications.
Producer-Consumer Pattern
The Producer-Consumer pattern is a common concurrent design pattern where one or more producers generate data, and one or more consumers process that data. This pattern can be implemented using channels in Go.
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
// Create a channel to pass data between producer and consumer
jobs := make(chan int, 100)
results := make(chan int, 100)
// Start the producer
go producer(jobs)
// Start the consumers
for w := 1; w <= 3; w++ {
go consumer(w, jobs, results)
}
// Wait for all the results
for i := 0; i < 100; i++ {
fmt.Println("Result:", <-results)
}
}
func producer(jobs chan<- int) {
for i := 0; i < 100; i++ {
jobs <- i
}
close(jobs)
}
func consumer(id int, jobs <-chan int, results chan<- int) {
for job := range jobs {
fmt.Printf("Consumer %d is processing job %d\n", id, job)
time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
results <- job * 2
}
}
Fan-In and Fan-Out Patterns
The Fan-In and Fan-Out patterns are used to distribute work across multiple Goroutines and then collect the results. The Fan-In pattern combines the results from multiple Goroutines into a single channel, while the Fan-Out pattern distributes work across multiple Goroutines.
graph LR
A[Input] --> B[Fan-Out]
B --> C[Worker 1]
B --> D[Worker 2]
B --> E[Worker 3]
C --> F[Fan-In]
D --> F
E --> F
F --> G[Output]
By understanding and applying these concurrent design patterns, you can write more scalable and efficient Go programs that take advantage of the language's concurrency features.