Go - 使用 sync.WaitGroup 來實現併發操作
阿新 • • 發佈:2021-11-01
目錄
前言
如果你有一個任務可以分解成多個子任務進行處理,同時每個子任務沒有先後執行順序的限制,等到全部子任務執行完畢後,再進行下一步處理。這時每個子任務的執行可以併發處理,這種情景下適合使用 sync.WaitGroup
。
雖然 sync.WaitGroup
使用起來比較簡單,但是一不留神很有可能踩到坑裡。
sync.WaitGroup 正確使用
比如,有一個任務需要執行 3 個子任務,那麼可以這樣寫:
func main() { var wg sync.WaitGroup wg.Add(3) go handlerTask1(&wg) go handlerTask2(&wg) go handlerTask3(&wg) wg.Wait() fmt.Println("全部任務執行完畢.") } func handlerTask1(wg *sync.WaitGroup) { defer wg.Done() fmt.Println("執行任務 1") } func handlerTask2(wg *sync.WaitGroup) { defer wg.Done() fmt.Println("執行任務 2") } func handlerTask3(wg *sync.WaitGroup) { defer wg.Done() fmt.Println("執行任務 3") }
執行輸出:
執行任務 3
執行任務 1
執行任務 2
全部任務執行完畢.
sync.WaitGroup 閉坑指南
01
// 正確
go handlerTask1(&wg)
// 錯誤
go handlerTask1(wg)
執行子任務時,使用的 sync.WaitGroup
一定要是 wg
的引用型別!
02
注意不要將 wg.Add()
放在 go handlerTask1(&wg)
中!
例如:
// 錯誤 var wg sync.WaitGroup go handlerTask1(&wg) wg.Wait() ... func handlerTask1(wg *sync.WaitGroup) { wg.Add(1) defer wg.Done() fmt.Println("執行任務 1") }
注意 wg.Add()
一定要在 wg.Wait()
執行前執行!
03
注意 wg.Add()
和 wg.Done()
的計數器保持一致!其實 wg.Done()
就是執行的 wg.Add(-1)
。
小結
sync.WaitGroup
使用起來比較簡單,一定要注意不要踩到坑裡。
其實 sync.WaitGroup
使用場景比較侷限,僅適用於等待全部子任務執行完畢後,再進行下一步處理,如果需求是當第一個子任務執行失敗時,通知其他子任務停止執行,這時 sync.WaitGroup
是無法滿足的,需要使用到通知機制(channel
)。
以上,希望對你能夠有所幫助。
推薦閱讀
- Go - 使用 sync.Map 解決 map 併發安全問題
- Go - 基於逃逸分析來提升程式效能
- Go - 使用 sync.Pool 來減少 GC 壓力
- Go - 使用 options 設計模式
- Go - 兩個在開發中需注意的小點
作者:新亮筆記(關注公眾號,可申請新增微信好友)
出處:https://www.cnblogs.com/xinliangcoder
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連線,否則保留追究法律責任的權利。