WaitGroup 死鎖:理解「所有Goroutine 都處於睡眠狀態- 死鎖!」
當嘗試使用WaitGroup 可能協調會遇到錯誤「致命錯誤:所有goroutine 都在睡覺- 死鎖!」。當負責遞減 WaitGroup 計數器的 goroutine 無意中結束睡眠時,就會發生這種情況。
問題:
以下Go 程式碼說明如何出現此錯誤:
package main import ( "fmt" "sync" ) func main() { var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go func() { defer wg.Done() fmt.Println("Hello", i) }() } wg.Wait() }
執行後,此程式碼應為每個goroutine 列印「Hello」。然而,程式卻以可怕的「死鎖」錯誤退出。
原因:
問題在於 WaitGroup 傳遞給 goroutine 的方式。當值傳遞給匿名函數時,Go 會產生該值的副本。因此,每個 goroutine 都在 WaitGroup 的單獨副本上運行,其中沒有一個副本的計數器遞減,從而導致 goroutine 永久睡眠。
解:
要解決死鎖,必須傳遞指向 WaitGroup 的指標而不是 WaitGroup 本身。因此,所有 goroutine 將引用相同的 WaitGroup,使它們能夠正確地遞減其計數器:
package main import ( "fmt" "sync" ) func main() { wg := &sync.WaitGroup{} for i := 0; i < 10; i++ { wg.Add(1) go func() { defer wg.Done() fmt.Println("Hello", i) }() } wg.Wait() }
透過傳遞指針,goroutines 共享相同的 WaitGroup 物件並可以成功協調它們的執行。此版本的程式碼將為每個 goroutine 正確列印“Hello”,而不會觸發死鎖。
以上是為什麼我的 Go WaitGroup 會導致'所有 Goroutine 都處於睡眠狀態 - 死鎖!”錯誤?的詳細內容。更多資訊請關注PHP中文網其他相關文章!