首页 >后端开发 >Golang >使用sync.WaitGroup时如何修复Go通道中的死锁错误?

使用sync.WaitGroup时如何修复Go通道中的死锁错误?

Patricia Arquette
Patricia Arquette原创
2024-10-29 02:36:02470浏览

How to Fix Deadlock Errors in Go Channels When Using sync.WaitGroup?

了解 Go Channel 中的死锁错误

在本文中,我们将分析“死锁”背后的原因!由以下代码片段中涉及 Go 通道的死锁情况引起的错误:

package main

import (
    "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)
    go pull(c, wg)

    wg.Wait()
}

运行此代码时,我们遇到以下错误:

throw: all goroutines are asleep - deadlock!

理解死锁

发生死锁是因为结构(例如此代码中的sync.WaitGroup)是按值传递而不是按引用传递。这意味着当我们将 WaitGroup 传递给我们的函数(推和拉)时,我们实际上传递的是 WaitGroup 的副本而不是原始对象。

因此,每个函数都在其自己的副本上工作WaitGroup 的副本,当它们调用 wg.Done() 时,它们会递减自己的副本。这不会更新我们的主协程正在等待的原始 WaitGroup,从而导致死锁。

修复死锁

要解决这个问题,我们需要传递指针到 WaitGroup 而不是值。这将确保推送和拉取函数都在 WaitGroup 的同一个实例上工作,并且它们对 wg.Done() 的调用将影响原始对象。

这是代码的更正版本:

package main

import (
    "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)
    go pull(c, &wg)

    wg.Wait()
}

通过进行此更改,我们现在将指向 WaitGroup 的指针传递给我们的函数,确保它们都在同一对象上工作并正确更新其状态。这消除了死锁情况,让我们的程序能够无错误地运行。

以上是使用sync.WaitGroup时如何修复Go通道中的死锁错误?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn