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