在 Golang 程序中,Channel 促进了 goroutine 之间的通信。然而,误用通道可能会导致死锁,如下面的代码所示:
<br>package main<p>import (</p><pre class="brush:php;toolbar:false">"fmt" "sync"
)
func push(c chan int, wgsync.WaitGroup) {
for i := 0; i < 5; i++ { c <- i } wg.Done()
}
func pull(c chan int, wgsync.WaitGroup) {
for i := 0; i < 5; i++ { result, ok := <-c fmt.Println(result, ok) } wg.Done()
}
func main() {
var wg sync.WaitGroup wg.Add(2) c := make(chan int) go push(c, wg) go pull(c, wg) wg.Wait() // Block the main thread until goroutines complete
}
运行此程序时,您可能会遇到出现以下错误:
fatal error: all goroutines are asleep - deadlock!
要理解为什么会发生这种死锁,让我们深入研究一下代码:
问题在于如何将 WaitGroup 传递给 goroutine。当传递的值不带与号 (&) 时,它是按值传递,而不是按引用传递。在这种情况下,将为每个 goroutine 创建一个 WaitGroup 的副本。
因此,当每个 goroutine 调用 wg.Done() 时,它会修改其本地的 WaitGroup 副本。由于主线程会一直等待,直到 wg 指示所有 Goroutine 都已完成,因此它会无限期地等待,因为两个 Goroutine 都不会更新原始的 WaitGroup。这会导致死锁。
要解决此问题,我们需要通过引用传递 WaitGroup。这可以确保两个 goroutine 修改 WaitGroup 的同一实例,并向主线程正确发出完成信号。
这是经过更正的代码修订版:
<br>package main<p>import (</p><pre class="brush:php;toolbar:false">"fmt" "sync"
)
func push(c chan int, wg *sync.WaitGroup) {
for i := 0; i < 5; i++ { c <- i } wg.Done()
}
func pull(c chan int, wg *sync.WaitGroup) {
for i := 0; i < 5; i++ { result, ok := <-c fmt.Println(result, ok) } wg.Done()
}
func main() {
var wg sync.WaitGroup wg.Add(2) c := make(chan int) go push(c, &wg) // Pass the WaitGroup by reference using the ampersand go pull(c, &wg) // Pass the WaitGroup by reference using the ampersand wg.Wait()
}
通过引用传递WaitGroup,我们确保主线程能够正确判断两个goroutines何时完成任务,从而避免死锁。
以上是为什么在 Go 中按值传递 WaitGroup 会导致死锁,如何解决?的详细内容。更多信息请关注PHP中文网其他相关文章!