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中文网其他相关文章!