Golang WaitGroup vs. errgroup:用途、差異與實務範例
在 Go 開發中,同步多個 Goroutine 的完成狀態常見兩大工具:標準庫
sync.WaitGroup與golang.org/x/sync/errgroup。本文從 API、錯誤處理、Context、併發控制 等面向比較兩者差異,並給出典型使用時機與程式碼範例。
一、核心概念
| 名稱 | 所屬套件 | 主要職責 |
|---|---|---|
| WaitGroup | sync (標準庫) |
計數同步:等待一組 Goroutine 全部執行完畢 |
| errgroup.Group | golang.org/x/sync/errgroup |
WaitGroup + 收集第一個錯誤 + Context 取消 + 併發上限 |
二、基本用法
1. WaitGroup
1 | var wg sync.WaitGroup |
特性:
- 僅負責計數,不傳遞錯誤。
- 需手動
Add/Done配對;漏呼叫易導致 deadlock。
2. errgroup.Group
1 | ctx := context.Background() |
特性:
Go(func() error)收集第一個 non-nil error 並回傳於Wait()。- 任何 Goroutine 回錯,
ctx即取消,其他 Goroutine 可感知停止。
三、差異比較
| 面向 | WaitGroup | errgroup.Group |
|---|---|---|
| 錯誤收集 | 無 | 收第一個 non-nil error |
| Context 整合 | 無 | WithContext 產生可取消 ctx |
| 併發上限 | 無,需自行 semaphore | errgroup.Group + parallelism (errgroup.WithContext 無限制;可搭配 semaphore 包) |
| API 簡潔度 | 低:需 Add/Done |
高:自動 Add/Done 於 Go() |
| 依賴 | 標準庫 | 外部套件 (x/sync) |
小貼士:若僅需同步且忽略錯誤,
WaitGroup足矣。若需錯誤傳遞或提前取消,請選擇errgroup。
四、併發上限範例 (semaphore 搭配 errgroup)
1 | eg, ctx := errgroup.WithContext(context.Background()) |
五、選用建議
| 場景 | 建議工具 | 原因 |
|---|---|---|
| 簡單並行計算,不關心錯誤 | WaitGroup | 最輕量、零依賴 |
| 需要錯誤即停、Context 取消 | errgroup | 簡單封裝、省去樣板碼 |
| 須限制同時併發量 | errgroup + semaphore | Go1.20 起可用 x/sync/semaphore |
| 舊專案、極度追求依賴零化 | WaitGroup | 不額外引入模組 |
六、常見陷阱
- WaitGroup 計數不平:
Add與Done不對等 → 永遠卡在Wait()。 - errgroup 忽視 ctx:Goroutine 內部未使用傳入 ctx → 無法提早中止。
- 併發過高:無限開 Goroutine,導致記憶體/FD 耗盡;應設限。
七、結語
sync.WaitGroup 與 errgroup.Group 分別代表 最小同步原語 與 高階錯誤協調工具。依需求選擇,搭配 Context 與併發控制,可讓你的 Goroutine 更加可控、可觀測。
記得:並發容易,協調不易。善用適合的工具,才能寫出優雅且健壯的並行程式!
All articles on this blog are licensed under CC BY-NC-SA 4.0 unless otherwise stated.
Comments











