面對(duì)goroutine我們都需要等待它完成交給它的事情,等待它計(jì)算完成或是執(zhí)行完畢,所以不得不在程序需要等待的地方使用time.Sleep()來睡眠一段時(shí)間,等待其他goroytine執(zhí)行完畢,下面的代碼打印1到100的for循環(huán)可以在很快的時(shí)間內(nèi)運(yùn)行完畢,但是我們必須添加time.Sleep()來等待其打印完畢,如果我們不等待仿佛什么也沒有發(fā)生一樣。。。。。這肯定不是我們想要的!
func main(){ for i := 0; i 100 ; i++{ go fmt.Println(i) } time.Sleep(time.Second) }
這就是我最開始學(xué)習(xí)goroutine想到的笨方法。。。。死等! 等不到 time.Second*2 在等不到*3
但是對(duì)于我們實(shí)際的使用場(chǎng)景來說,1秒也許等待的時(shí)間有點(diǎn)長(zhǎng),而有時(shí)候是遠(yuǎn)遠(yuǎn)不夠的,最主要的我們無法預(yù)知gorotine的運(yùn)行時(shí)間長(zhǎng)短,所以也無法指定Sleep睡眠的時(shí)間。
正好前幾天學(xué)習(xí)了channel,那么現(xiàn)在我們就可以
func main() { c := make(chan bool, 100) for i := 0; i 100; i++ { go func(i int) { fmt.Println(i) c - true }(i) } for i := 0; i 100; i++ { -c } }
完美輸出!這里我們可以從控制臺(tái)看到我們的勝利成果,但是我們有更好的處理方式:sync.WaitGroup
WaitGroup對(duì)象內(nèi)部有一個(gè)計(jì)數(shù)器,最初從0開始,它有三個(gè)方法:Add() Done() Wait() 用來控制計(jì)數(shù)器的數(shù)量從而達(dá)到等待的目的。
func main() { wg := sync.WaitGroup{} wg.Add(100) for i := 0; i 100; i++ { go func(i int) { defer wg.Done() fmt.Print(i) }(i) } wg.Wait() }
首先使用 add(100) 把計(jì)數(shù)器的數(shù)量設(shè)置為100,每次循環(huán)運(yùn)行完畢都把計(jì)數(shù)器減1,主函數(shù)使用Wait()
阻塞,直到計(jì)數(shù)器歸0結(jié)束主線程結(jié)束阻塞。
這里會(huì)阻塞主線程?。。⌒枰⒁?。
type WaitGroup struct { noCopy noCopy state1 [3]uint32 }
它只是一個(gè)struct所以當(dāng)參數(shù)傳遞的時(shí)候需要傳遞指針。
補(bǔ)充:sync.WaitGroup的錯(cuò)誤用法與糾正
本文主要是記錄在學(xué)習(xí)golang語言過程中錯(cuò)誤使用sync.WaitGroup以及指針引起的報(bào)錯(cuò),并且糾正過程。
package main import ( "fmt" "pressure/game" "sync" ) var waitGroup sync.WaitGroup //定義一個(gè)同步等待的組 func main(){ waitGroup.Add(1) //添加一個(gè)計(jì)數(shù) go game.ConnSocket(serverAddr, waitGroup) //調(diào)用其他包的方法執(zhí)行任務(wù) waitGroup.Wait() //阻塞直到所有任務(wù)完成 fmt.Println("main DONE!!!") }
package game import ( "fmt" "net" "strconv" "strings" "sync" ) var gameWait sync.WaitGroup func ConnSocket(serverAddr string, wait sync.WaitGroup) { var err error Conn, err = net.Dial("tcp", serverAddr) if err != nil { fmt.Println("Error connected:", err.Error()) wait.Done() return } gameWait = wait fmt.Println("connected OK:", Conn.RemoteAddr()) go readMessage() } func readMessage() { fmt.Println("readMessage:") for { if OK:=dosomething(),OK{ gameWait.Done() } } }
然后執(zhí)行如上的代碼,會(huì)出現(xiàn)報(bào)錯(cuò):
panic: sync: negative WaitGroup counter
goroutine 12 [running]:
sync.(*WaitGroup).Add(0x7b8b90, 0xffffffffffffffff)
D:/Program Files/Go/src/sync/waitgroup.go:75 +0x1d0
sync.(*WaitGroup).Done(0x7b8b90)
原因:
func ConnSocket(serverAddr string, wait sync.WaitGroup)只是把sync.WaitGroup的值傳遞過來,而非內(nèi)存地址,所以在賦值給gameWait的時(shí)候也只是賦值了值,gameWait并非指向的main里的waitGroup 的內(nèi)存地址,導(dǎo)致 gameWait.Done()的時(shí)候并沒有獲取到main里的計(jì)數(shù)1,所以才會(huì)報(bào)負(fù)數(shù)。究其原因還是沒有對(duì)指針的理解。所以針對(duì)上面的問題做了修改。
package main import ( "fmt" "pressure/game" "sync" ) var waitGroup sync.WaitGroup //定義一個(gè)同步等待的組 func main(){ waitGroup.Add(1) //添加一個(gè)計(jì)數(shù) //這里傳遞waitGroup的內(nèi)存地址 go game.ConnSocket(serverAddr, waitGroup) //調(diào)用其他包的方法執(zhí)行任務(wù) waitGroup.Wait() //阻塞直到所有任務(wù)完成 fmt.Println("main DONE!!!") }
package game import ( "fmt" "net" "strconv" "strings" "sync" ) var gameWait *sync.WaitGroup//此處也申明為指針變量 //參數(shù)傳遞為指針傳遞*sync.WaitGroup,即wait 指向的是main里的waitGroup的內(nèi)存地址 func ConnSocket(serverAddr string, wait *sync.WaitGroup) { var err error Conn, err = net.Dial("tcp", serverAddr) if err != nil { fmt.Println("Error connected:", err.Error()) wait.Done() return } gameWait = wait//指針指向另一個(gè)指針,這樣就做到了gameWait指向的是wait的地址,所以gameWait修改wait的內(nèi)存地址鎖存貯的值也會(huì)跟隨改變 fmt.Println("connected OK:", Conn.RemoteAddr()) go readMessage() } func readMessage() { fmt.Println("readMessage:") for { if OK:=dosomething(),OK{ gameWait.Done() } } }
還是對(duì)指針傳遞以及值傳遞理解不夠透徹才會(huì)出現(xiàn)如此問題,因此還需要多針對(duì)指針進(jìn)行學(xué)習(xí)與理解。以防在以后的工作中出現(xiàn)類似問題。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。
標(biāo)簽:雞西 重慶 銅川 梅河口 汕頭 欽州 吐魯番 蘭州
巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《在golang中使用Sync.WaitGroup解決等待的問題》,本文關(guān)鍵詞 在,golang,中,使用,Sync.WaitGroup,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。