---
title: Go 並行回顧 2026-09-22
created: 2026-09-22
lang: zh-Hant
---

# Go 並行回顧

## 只收第一個值，誰還沒結束？

producer 依序送出 2、4、6；consumer 收到 2 就返回。若用無緩衝 channel，後面又沒人接收，producer 會卡在送出 4。consumer 返回，不會連帶終止 producer。

讓傳送同時等待接收者或取消通知：

```go
select {
case out <- value:
case <-ctx.Done():
    return
}
```

consumer 不再需要結果時呼叫 cancel。這裡只有一個 producer，由它在 goroutine 開頭安排 `defer close(out)`，結束時關閉輸出。

## 三個邊界

| 機制 | 能做什麼 | 不能保證什麼 |
|---|---|---|
| channel | 無緩衝 send 等到接收者就緒；有緩衝時可先填入空位 | 接收者離開後，sender 會自行結束 |
| close | 表示不再送值；已緩衝的值仍可取出，耗盡後 receive 得到零值與 false | 取消還在執行的 goroutine；向已關閉 channel 傳送會 panic |
| context | 透過 Done 通知工作取消 | 強制中斷工作，或等待工作結束 |

取消是合作機制。迴圈必須檢查 Done；阻塞的 I/O 也要支援 context。若 send 與 Done 同時就緒，select 可能選到 send，不能假設取消有優先權。

## 工作變多時

固定啟動 N 個 worker，從 jobs channel 取工作，可限制同時執行的工作數。任務佇列與結果 channel 也要有容量與取消策略，不能只限制 worker 數就宣稱記憶體有上限。

多個 worker 共用輸出時，由協調者等待所有 sender 結束，再關閉輸出；不要讓每個 worker 各自 close。需要確認全部退出時，用 WaitGroup 等待，不能以 cancel 返回代替。

## 依據

- [Go 官方：Pipelines and cancellation](https://go.dev/blog/pipelines) — 提前停止接收、取消、固定 worker 與關閉輸出的責任。
- [context 文件](https://pkg.go.dev/context#WithCancel) — Done 與取消；CancelFunc 不等待工作結束。
- [Go 語言規格：Send statements](https://go.dev/ref/spec#Send_statements)、[Close](https://go.dev/ref/spec#Close)、[Select statements](https://go.dev/ref/spec#Select_statements) — 阻塞、關閉與就緒分支的選擇。
