2 回答

TA貢獻(xiàn)1828條經(jīng)驗(yàn) 獲得超13個(gè)贊
wg.Add()
在啟動(dòng)將調(diào)用的 goroutine 之前,您應(yīng)該始終調(diào)用wg.Done()
.
在您更正的示例中,main
goroutine 只能wg.Wait()
在for
循環(huán)之后到達(dá),這可以保證您調(diào)用wg.Add()
一百次,因此wg.Wait()
會(huì)阻塞直到wg.Done()
被調(diào)用100
次數(shù)。
當(dāng)wg.Add()
調(diào)用在新的 goroutine 中時(shí),不能保證任何wg.Add()
調(diào)用都會(huì)在main
goroutine 到達(dá)之前執(zhí)行,wg.Wait()
因?yàn)樗鼈兪遣l(fā)運(yùn)行的(在此之前沒有同步)。這種情況下的行為是不確定的(取決于 goroutine 調(diào)度程序,它在沒有顯式同步的情況下是不確定的)。
請(qǐng)注意,如果您知道循環(huán)100
進(jìn)行迭代,另一種選擇是wg.Add(100)
在循環(huán)之前調(diào)用。我建議不要這樣做,因?yàn)楫?dāng)循環(huán)包含break
或continue
操作時(shí),這需要小心,這可能會(huì)導(dǎo)致啟動(dòng)的 goroutine 更少,從而最終你的main
goroutine 會(huì)卡住。是的,在您的情況下,這可能是微不足道的,但如果此代碼及時(shí)發(fā)展,它可能會(huì)變得不那么明顯,并可能導(dǎo)致未來的錯(cuò)誤。當(dāng)場(chǎng)景中涉及啟動(dòng) goroutine 時(shí),說它更快是無(wú)關(guān)緊要的。如果您只wg.Add(1)
在啟動(dòng) goroutine 之前調(diào)用,那么稍后您是否有條件地跳過這部分也沒關(guān)系,因?yàn)槟鷮⒃?code>wg.Add()啟動(dòng) goroutine 的同時(shí)跳過,并且您的代碼將保持正確。
使用時(shí)要遵循的簡(jiǎn)單“規(guī)則” sync.WaitGroup
:(引自this answer)
在語(yǔ)句之前調(diào)用
WaitGroup.Add()
“原始”goroutine(開始一個(gè)新的)go
建議調(diào)用
WaitGroup.Done()
deferred,所以即使 goroutine 發(fā)生恐慌它也會(huì)被調(diào)用如果你想傳遞
WaitGroup
給其他函數(shù)(而不是使用包級(jí)變量),你必須傳遞一個(gè)指向它的指針,否則WaitGroup
(這是一個(gè)結(jié)構(gòu))將被復(fù)制,并且Done()
不會(huì)觀察到在復(fù)制上調(diào)用的方法在原版上

TA貢獻(xiàn)1829條經(jīng)驗(yàn) 獲得超7個(gè)贊
就像其他人提到的那樣wg.add(),應(yīng)該在調(diào)用任何 go 例程之前調(diào)用。所以在主線程里面:
一開始就推遲是一種很好的做法,這樣你就不會(huì)忘記,因?yàn)樗灰暈榍謇硇袆?dòng)。
var wg sync.WaitGroup
var v int32 = 0
for i = 0; i < 100; i++{
wg.Add(1) //right place to put wg.add(1)
go func(){
defer wg.Done()
atomic.AddInt32(&v,1)
}
}
wg.Wait()
fmt.Println(v)
- 2 回答
- 0 關(guān)注
- 545 瀏覽
添加回答
舉報(bào)