Go 中的死鎖:「所有Goroutine 都處於睡眠狀態」
在使用Goroutine 時,有效管理通道操作以避免死鎖至關重要。當所有 goroutine 無限期地阻塞時,就會發生這種情況,從而導致死鎖情況。
理解程式碼
讓我們檢查一下提供的程式碼:
package main import ( "fmt" "sync" "time" ) type Item struct { name string } type Truck struct { Cargo []Item name string } func UnloadTrucks(c chan Truck) { for t := range c { fmt.Printf("%s has %d items in cargo: %s\n", t.name, len(t.Cargo), t.Cargo[0].name) } } func main() { trucks := make([]Truck, 2) ch := make(chan Truck) for i, _ := range trucks { trucks[i].name = fmt.Sprintf("Truck %d", i+1) fmt.Printf("Building %s\n", trucks[i].name) } for t := range trucks { go func(tr Truck) { itm := Item{} itm.name = "Groceries" fmt.Printf("Loading %s\n", tr.name) tr.Cargo = append(tr.Cargo, itm) ch <- tr }(trucks[t]) } time.Sleep(50 * time.Millisecond) fmt.Println("Unloading Trucks") UnloadTrucks(ch) fmt.Println("Done") }
此程式碼建立一個Truck 類型的通道ch 並啟動兩個goroutine 來模擬用雜貨裝載卡車並將它們發送到頻道。然後它調用 UnloadTrucks 檢索並列印卡車的內容。
死鎖原因
問題在於缺乏關閉 ch 通道的機制。當所有 goroutine 都將卡車發送到通道時,UnloadTrucks 中沒有終止循環的訊號。這意味著 ch 會一直監聽永遠不會到達的值,導致死鎖。
解決方案
要解決死鎖,我們需要在以下情況下明確關閉 ch 通道:載入 goroutine 已完成。我們可以使用sync.WaitGroup來計算正在運行的goroutines,並在所有goroutines完成後關閉通道:
var wg sync.WaitGroup go func() { wg.Wait() close(ch) }() UnloadTrucks(ch)
此修改確保一旦所有goroutines完成裝載卡車,UnloadTrucks將終止。 Wait 函數會阻塞,直到 WaitGroup 計數器達到零,這表示所有 goroutine 都已完成其工作。關閉通道會向 UnloadTrucks 發出不再接收卡車的信號,使其優雅地退出循環。
以上是當所有 Goroutine 都處於睡眠狀態時,如何解決 Go 中的死鎖?的詳細內容。更多資訊請關注PHP中文網其他相關文章!