2 回答

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

TA貢獻1829條經驗 獲得超7個贊
就像其他人提到的那樣wg.add(),應該在調用任何 go 例程之前調用。所以在主線程里面:
一開始就推遲是一種很好的做法,這樣你就不會忘記,因為它被視為清理行動。
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 關注
- 556 瀏覽
添加回答
舉報