Go 中的死锁:“所有 go 例程都在睡眠”
运行提供的代码时,由于其异步执行模型而发生死锁使用 goroutine。在将任何卡车发送到通道之前调用 UnloadTrucks 函数时,就会出现问题。这会导致通道保持空状态,导致发送者 goroutine 在 ch
解决方案:使用 WaitGroup 关闭通道
为了解决死锁,我们可以在所有 goroutine 发送完卡车后关闭通道 ch。这可以通过引入 WaitGroup 来实现,这是一个跟踪待处理 goroutine 数量的同步原语:
go func() { wg.Wait() close(ch) }()
此 goroutine 会等待,直到所有其他 goroutine 完成其任务(由 Wait() 调用发出信号)。关闭通道。通过这样做,UnloadTrucks 函数能够在所有卡车发送完毕后正常退出。
修改后的代码:
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) var wg sync.WaitGroup 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 wg.Done() }(trucks[t]) wg.Add(1) } time.Sleep(50 * time.Millisecond) fmt.Println("Unloading Trucks") UnloadTrucks(ch) fmt.Println("Done") }
使用此修改后的代码,死锁被消除是因为 UnloadTrucks 函数保证在通道关闭之前接收到所有卡车。这可以确保所有 goroutine 正确完成其任务,并且程序运行不会出现任何意外中断。
以上是如何解决异步操作和空通道导致的Go死锁?的详细内容。更多信息请关注PHP中文网其他相关文章!