WaitGroup 死锁:理解“所有 Goroutine 都处于睡眠状态 - 死锁!”
当尝试使用 WaitGroup 协调 Goroutines 时,可能会遇到错误“致命错误:所有 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中文网其他相关文章!