網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
一、前言
waitgroup在golang中,用于線程同步,指等待一個(gè)組,等待一個(gè)系列執(zhí)行完成后,才會(huì)向下執(zhí)行,可以解決一個(gè) 進(jìn)程goroutine 等待多個(gè)該進(jìn)程啟動(dòng)的子線程goroutine 都正常運(yùn)行完成的場(chǎng)景,這個(gè)比較常見(jiàn)的場(chǎng)景就是例如 后端 main processer 啟動(dòng)了多個(gè)消費(fèi)者worker干活,還有爬蟲并發(fā)爬取數(shù)據(jù),多線程下載等等,為了保證主進(jìn)程在所有的子線程完成后再退出,這時(shí)就要用上waitgroup
二、waitgroup使用示例
我們這里模擬一個(gè) worker 的例子
package main import ( "fmt" "sync" "time" ) func worker(idx int, out chan struct{}, wg *sync.WaitGroup) { defer wg.Done() time.Sleep(1 * time.Second) fmt.Println(time.Now()) fmt.Println(idx ) <-out } func main() { wg := new(sync.WaitGroup) in := make(chan struct{}, 20) for i := 0; i < 200; i++ { in <- struct{}{} wg.Add(1) go worker(i, in, wg) } wg.Wait() }
在這段代碼中,main最后一行是
wg.Wait()
這行代碼保證有所的200個(gè)子線程全部都執(zhí)行完成后才會(huì)退出main函數(shù),如果沒(méi)有最后一行wg.Wait(),可能會(huì)出現(xiàn)for循環(huán)遍歷完程序就直接退出了,有可能只有不確定個(gè)幾個(gè)子線程執(zhí)行完成,其它線程由于主程序main退出后就直接退出了
從這個(gè)例子我們也可以看到 waitgroup通常配合來(lái)限制并發(fā)線程個(gè)數(shù)和確保所有的線程都最終都執(zhí)行完成
這段代碼中 ws 有三個(gè)緩沖,所以并發(fā)的數(shù)量是20,超過(guò)20個(gè)就要等待執(zhí)行完成釋放所占用通道后才能再開新的線程
上面的代碼,會(huì)在執(zhí)行到wg.Wait()后等待,直到所有的200線程全部執(zhí)行完后才會(huì)繼續(xù)往下執(zhí)行
可以説這段代碼非常精妙,示例代碼執(zhí)行結(jié)果如下:
同時(shí)我們也可以測(cè)試一下把最后一行
//wg.Wait()
注釋掉,我們看一下程序會(huì)怎么執(zhí)行
注釋后,我們看到程序完成時(shí),只有171個(gè)線程完成運(yùn)行,剩下的20幾個(gè)線程異常結(jié)束了,看不到任何返回結(jié)果
三、waitgroup使用注意事項(xiàng)
同時(shí)我們?cè)谑褂脀aitgroup時(shí)也要注意一些坑:
1、 Add一個(gè)負(fù)數(shù)
如果計(jì)數(shù)器的值小于0會(huì)直接panic
2、 Add在Wait之后調(diào)用
比如一些子協(xié)程開頭調(diào)用Add結(jié)束調(diào)用Wait,這些 Wait無(wú)法阻塞子協(xié)程。正確做法是在開啟子協(xié)程之前先Add特定的值。
3、 未置為0就重用
WaitGroup可以完成一次編排任務(wù),計(jì)數(shù)值降為0后可以繼續(xù)被其他任務(wù)所用,但是不要在還沒(méi)使用完的時(shí)候就用于其他任務(wù),這樣由于帶著計(jì)數(shù)值,很可能出問(wèn)題。
4、 復(fù)制waitgroup
WaitGroup有nocopy字段,不能被復(fù)制。也意味著WaitGroup不能作為函數(shù)的參數(shù)
四、waitgroup使用總結(jié)
WaitGroup是Golang應(yīng)用開發(fā)過(guò)程中經(jīng)常使用的并發(fā)控制技術(shù),學(xué)習(xí)golang是我們必須要掌握和理解的機(jī)制之一,建議有時(shí)間了大家再進(jìn)一步的研究一下WaitGroup的底層實(shí)現(xiàn)邏輯。
附:陷阱避免
1)WaitGroup 同步的是 goroutine, 如果在 goroutine 中進(jìn)行 Add(1) 操作,可能在這些 goroutine 還沒(méi)來(lái)得及 Add(1) 已經(jīng)執(zhí)行 Wait 操作,造成程序退出。
2)WaitGroup 傳遞給goroutine的時(shí)候,應(yīng)該采用引用方式,從而避免發(fā)生副本拷貝而死鎖。
總結(jié)
原文鏈接:https://blog.csdn.net/itopit/article/details/125525681
相關(guān)推薦
- 2023-06-04 C#中+=是什么意思及+=的用法_C#教程
- 2022-09-18 jenkins配置golang?代碼工程自動(dòng)發(fā)布的實(shí)現(xiàn)方法_Golang
- 2022-05-28 基于ASP.NET實(shí)現(xiàn)驗(yàn)證碼生成詳解_實(shí)用技巧
- 2022-04-23 C#多線程系列之a(chǎn)sync和await用法詳解_C#教程
- 2022-07-04 Python異步處理返回進(jìn)度——使用Flask實(shí)現(xiàn)進(jìn)度條_python
- 2022-07-26 Nginx本地配置SSL訪問(wèn)的實(shí)例教程_nginx
- 2023-01-03 C++?Boost?MetaStateMachine定義狀態(tài)機(jī)超詳細(xì)講解_C 語(yǔ)言
- 2023-01-02 Kotlin類對(duì)象class初始化與使用_Android
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支