Goroutine + Channel 組合出來的幾個經典模式。實務上幾乎所有併發程式都是這幾種模式的變形。
Worker Pool#
固定數量的 worker 從同一個 jobs channel 拉工作、結果寫到 results channel。
flowchart LR
J[Jobs Channel] --> W1[Worker 1]
J --> W2[Worker 2]
J --> W3[Worker 3]
W1 --> R[Results Channel]
W2 --> R
W3 --> Rfunc workerPool(numWorkers int, jobs <-chan int, results chan<- int) {
var wg sync.WaitGroup
for i := 0; i < numWorkers; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
for job := range jobs {
results <- process(job)
}
}(i)
}
wg.Wait()
close(results)
}
func main() {
jobs := make(chan int, 100)
results := make(chan int, 100)
// 啟動 worker pool
go workerPool(5, jobs, results)
// 傳送工作
for i := 0; i < 50; i++ {
jobs <- i
}
close(jobs)
// 收集結果
for result := range results {
fmt.Println(result)
}
}Pipeline#
每個階段是獨立的 goroutine,用 channel 把輸出串到下一個階段的輸入。
flowchart LR
A[generator<br>產生資料] -->|chan int| B[square<br>平方運算]
B -->|chan int| C[consumer<br>消費結果]func generator(nums ...int) <-chan int {
out := make(chan int)
go func() {
for _, n := range nums {
out <- n
}
close(out)
}()
return out
}
func square(in <-chan int) <-chan int {
out := make(chan int)
go func() {
for n := range in {
out <- n * n
}
close(out)
}()
return out
}
func main() {
// 建立 pipeline
nums := generator(1, 2, 3, 4, 5)
squared := square(nums)
// 消費結果
for result := range squared {
fmt.Println(result)
}
}Fan-out / Fan-in#
把工作從一個 channel 分散給多個 goroutine(fan-out),再把多個結果 channel 合併回一個(fan-in)。
flowchart TB
subgraph Fan-out
IN[Input Channel] --> W1[Worker 1]
IN --> W2[Worker 2]
IN --> W3[Worker 3]
end
subgraph Fan-in
W1 --> OUT[Output Channel]
W2 --> OUT
W3 --> OUT
end// Fan-out:多個 goroutine 讀取同一 channel
func fanOut(in <-chan int, n int) []<-chan int {
outs := make([]<-chan int, n)
for i := 0; i < n; i++ {
outs[i] = worker(in)
}
return outs
}
// Fan-in:合併多個 channel 到單一 channel
func fanIn(channels ...<-chan int) <-chan int {
var wg sync.WaitGroup
out := make(chan int)
for _, ch := range channels {
wg.Add(1)
go func(c <-chan int) {
defer wg.Done()
for v := range c {
out <- v
}
}(ch)
}
go func() {
wg.Wait()
close(out)
}()
return out
}Fan-out 適合 CPU bound 工作(用 worker 數 ≈ CPU 核心數);fan-in 用一個額外 goroutine + WaitGroup 確保所有來源關閉後才 close output。