在Go語言并發編程中,我們經常需要等待多個 goroutine 執行完畢后再繼續下一步操作。Go 提供的?
sync.WaitGroup
?就是專為這種**“等待一組任務完成”**而設計的同步原語。
一、基本原理
sync.WaitGroup
?提供三個主要方法:
方法 | 說明 |
Add(n int) | 設置等待的 goroutine 數量(加計數) |
Done() | 每個 goroutine 完成時調用(減計數) |
Wait() | 阻塞主 goroutine,直到計數歸零 |
它內部使用計數器+條件變量,當所有 goroutine 都調用?Done()
?后,Wait()
?才會解除阻塞。
二、典型用法
示例:等待 10 個 goroutine 執行完畢
package?mainimport?("fmt""sync"
)func?worker(id?int,?wg?*sync.WaitGroup)?{defer?wg.Done()?//?每個?goroutine?完成時調用fmt.Printf("Worker?%d?is?working...\n",?id)//?模擬工作
}func?main()?{var?wg?sync.WaitGroupfor?i?:=?1;?i?<=?10;?i++?{wg.Add(1)?//?每啟動一個?goroutine,加1go?worker(i,?&wg)}wg.Wait()?//?阻塞直到所有?goroutine?完成fmt.Println("All?workers?done.")
}
輸出示意:
Worker?1?is?working...
Worker?2?is?working...
...
All?workers?done.
三、常見錯誤及注意事項
1.?Add()
?必須在 goroutine 啟動前調用
錯誤示例:
go?func()?{wg.Add(1)?//?此時?goroutine?可能已開始執行,競態風險...
}()
正確做法:
wg.Add(1)
go?func()?{...wg.Done()
}()
2. 不可重復使用已完成的 WaitGroup(沒有“重置”功能)
WaitGroup 設計為一次性同步器,不建議重復使用,若確需控制并發次數,可用?sync.Pool
?或?semaphore
?替代。
四、結合匿名函數使用
for?i?:=?0;?i?<?5;?i++?{wg.Add(1)go?func(i?int)?{defer?wg.Done()fmt.Println("i:",?i)}(i)
}
wg.Wait()
?? 注意:傳參?i
?必須顯式傳入閉包,避免捕獲變量陷阱。
五、使用場景
- ? 等待一組任務執行完成(如:并發下載、批量計算)
- ? 控制主函數在 goroutine 完成后再退出
- ? 可搭配 Channel 和 Context 使用,實現更復雜的并發控制模型
六、小結
- ??
sync.WaitGroup
?是 Go 并發編程中最常用的同步工具之一。 - ? 使用?
Add
/Done
/Wait
?實現多協程間的同步等待。 - ? 使用時避免競態和變量捕獲問題。