首页  >  文章  >  后端开发  >  Golang中使用Goroutines和Channel时如何防止死锁?

Golang中使用Goroutines和Channel时如何防止死锁?

Susan Sarandon
Susan Sarandon原创
2024-10-27 06:48:29493浏览

How to Prevent Deadlock in Golang When Using Goroutines and Channels?

解决 Goroutine 死锁

在使用并发 Golang 程序时,可能会遇到死锁错误:“fatal error: all goroutine are sleep -僵局!”。当多个 goroutine 互相等待执行任务时会出现此错误,从而造成死锁情况。

考虑以下代码:

<code class="go">func producer(ch chan int, d time.Duration, num int) {
    for i := 0; i < num; i++ {
        ch <- i
        time.Sleep(d)
    }
}

func main() {
    ch := make(chan int)

    go producer(ch, 100*time.Millisecond, 2)
    go producer(ch, 200*time.Millisecond, 5)

    for {
        fmt.Println(<-ch)    
    }

    close(ch)
}</code>

此代码创建两个发送值的生产者 goroutine到同一个频道。主协程无限循环地不断从通道接收值。

问题的出现是因为生产者是“短暂的”,在有限的时间后停止发送值,但主协程继续接收值不休。这会造成死锁,因为通道永远不会关闭以发出不再发送任何值的信号。

为了解决此死锁,我们必须确保当所有生产者完成其任务时关闭通道。实现此目的的有效方法是使用同步原语,例如sync.WaitGroup。

这是代码的修改版本:

<code class="go">func producer(ch chan int, d time.Duration, num int, wg *sync.WaitGroup) {
    defer wg.Done()

    for i := 0; i < num; i++ {
        ch <- i
        time.Sleep(d)
    }
}

func main() {
    wg := &sync.WaitGroup{}
    ch := make(chan int)

    wg.Add(1)
    go producer(ch, 100*time.Millisecond, 2, wg)
    wg.Add(1)
    go producer(ch, 200*time.Millisecond, 5, wg)

    go func() {
        wg.Wait()
        close(ch)
    }()

    for v := range ch {
        fmt.Println(v)
    }
}</code>

在此代码中,我们传递了一个sync.WaitGroup。 WaitGroup 到每个生产者 goroutine。每个生产者在开始之前递增等待组,并在完成时递减。主协程使用 wg.Wait() 等待所有生产者完成。一旦所有生产者完成工作,主协程就会关闭通道。

此解决方案确保只有在所有生产者完成工作后才关闭通道,从而防止出现死锁情况。

以上是Golang中使用Goroutines和Channel时如何防止死锁?的详细内容。更多信息请关注PHP中文网其他相关文章!

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