首页  >  文章  >  后端开发  >  当使用 WaitGroup 和缓冲区有限的通道时,如何避免 Go 中的死锁?

当使用 WaitGroup 和缓冲区有限的通道时,如何避免 Go 中的死锁?

Mary-Kate Olsen
Mary-Kate Olsen原创
2024-10-27 01:21:02959浏览

How can you avoid deadlock in Go when using WaitGroup and a channel with a limited buffer?

Go 中 WaitGroup 和 Channel 的死锁

在 Go 中,当两个或多个 Goroutine 无限期地等待另一个 Goroutine 完成时,就会发生死锁。在此示例中,我们将探讨由于通道缓冲区不足和使用 WaitGroup 的 goroutine 同步不当而导致的死锁问题。

代码

<code class="go">package main

import "fmt"
import "sync"

func main() {
    ch := make(chan []int, 4)
    var m []int

    var wg sync.WaitGroup
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            ch <- m
            return
        }()
    }
    wg.Wait()

    for c := range ch {
        fmt.Printf("c is %v", c)
    }
}</code>

问题

代码尝试通过大小为 4 的缓冲通道发送 5 个值。但是,当通道已满时,它会阻塞,直到接收器可用为止。由于所有正在发送的 Goroutine 都已完成,因此没有一个可以从通道接收。

此外,在通道上运行的 Goroutine(对于 c := range ch)也会无限期地保持阻塞状态,因为它需要更多值即使没有发送更多内容,也能到达通道。这会造成发送方和接收方互相等待的死锁。

解决方案 1:增加通道缓冲区并关闭它

避免死锁的一种解决方案是将通道缓冲区大小增加到大于或等于发送 goroutine 数量的值。另外,所有发送完成后,通道应该关闭,表示不会再收到任何值。

<code class="go">ch := make(chan []int, 5)
...
wg.Wait()
close(ch)</code>

解决方案 2:在接收 Goroutine 中执行 Done()

另一种解决方案是在接收 goroutine 中而不是在 main 函数中执行 Done() 。通过这样做,WaitGroup 不会递减,直到 goroutine 接收并消耗该值:

<code class="go">func main() {
    ch := make(chan []int, 4)
    var m []int

    var wg sync.WaitGroup
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go func() {
            ch <- m
            return
        }()
    }
    go func() {
        for c := range ch {
            fmt.Printf("c is %v\n", c)
            wg.Done()
        }
    }()
    wg.Wait()
}</code>

以上是当使用 WaitGroup 和缓冲区有限的通道时,如何避免 Go 中的死锁?的详细内容。更多信息请关注PHP中文网其他相关文章!

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