首页  >  文章  >  后端开发  >  当生产者寿命较短时,如何避免 Go Goroutine 死锁?

当生产者寿命较短时,如何避免 Go Goroutine 死锁?

Linda Hamilton
Linda Hamilton原创
2024-10-25 07:09:02784浏览

How to Avoid Deadlock in Go Goroutines When Producers Are Short-Lived?

解决 Go Goroutine 中的死锁

在并发编程中,当多个 Goroutine 无限期地等待彼此完成操作时,就会发生死锁,从而有效地停止进程程序。本文解决了 Go 并发中遇到的特定死锁,如原始问题中所述:

<code class="go">package main

import (
    "fmt"
    "time"
)

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>

此代码由于以下因素触发死锁错误:

  • 生产者向通道发送值的过程是短暂的,最终会停止产生数据。
  • 主函数中的无限 for 循环不断从通道接收值,没有终止条件。
  • 无限循环后通道关闭,导致没有更多的值可用于接收。

解决方案:协调终止

为了避免死锁,生产者必须协调以发出完成信号,并且通道必须由最后一个生产者关闭。这是使用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>

在此解决方案中:

  • 我们为每个生产者增加WaitGroup。
  • 每个生产者通过 defer 语句在完成后递减 WaitGroup。
  • goroutine 等待 WaitGroup 达到零(意味着所有生产者都完成)并关闭通道。
  • 主循环使用 for range构造以在关闭之前迭代通道上发送的值。

以上是当生产者寿命较短时,如何避免 Go Goroutine 死锁?的详细内容。更多信息请关注PHP中文网其他相关文章!

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