一个通道有一个接收者和未知数量的 goroutine 发送者导致死锁

2024-04-20

我有一个频道,接收器是主要的。我生成多个 goroutine,每个 goroutine 通过通道发送一个字符串。

现在,这会导致死锁,因为我没有使用 close 函数正确关闭通道。问题是,我不知道将创建多少个 goroutine,因此无法知道何时关闭通道。

我尝试过使用 WaitGroup,问题是,我读到我不能在 goroutine 中使用 Add,我应该在主进程/goroutine 中使用 wg.Add(1),我尝试过使用 Add in父 Goroutine 生成子 Goroutine,这也导致了死锁

包主

import (
    "fmt"
    "sync"
)

var i = 0

func doSomething(ch chan string, wg sync.WaitGroup) {
    defer wg.Done()
    ch <- fmt.Sprintf("doSomething: %d", i)
    i++
    if i == 10 {return}
    wg.Add(1)
    go doSomething(ch, wg)
}

func main() {
    ch := make(chan string)
    var wg sync.WaitGroup
    wg.Add(1)
    go doSomething(ch, wg)
    wg.Wait()
    for s := range ch {
        fmt.Println(s)
    }
}

现在,这只是一个测试代码,所以,假设我们不知道我们只会创建 10 个 goroutine,假设它在运行时是未知的,这里如果我不使用,我会立即得到一个死锁错误,没有任何输出WorkGroup 在打印第 10 个字符串之前出现错误(因为我没有关闭通道)

我还尝试过不为每个函数调用生成一个 goroutine,而是对所有递归调用(从 main 开始)使用一个 goroutine,并且为了关闭通道,我为 go 创建了一个匿名函数,它首先调用 doSomething 函数,然后调用close,因此所有递归调用都将被评估,我们肯定知道何时关闭通道。但是,这就是我现在正在努力实现的目标,我正在尝试让未知数量的 goroutine 一起工作,并在完成后关闭通道。


有几个问题。

第一个是程序在将等待组值作为参数传递时复制它们。复制时等待组无法正常工作。相反,将指针传递给等待组。

第二个问题是 main 在从通道接收值之前等待所有 goroutine 完成。由于通道的缓冲区不够大,无法容纳所有发送的值,因此程序会死锁。

第三个问题是,主要波动超过了通道,但没有任何东西能够关闭通道。结果 Main 不会退出。

为了解决第二和第三个问题,启动另一个 goroutine 来等待doSomthing并在完成后关闭通道。

尝试这个:

func doSomething(ch chan string, wg *sync.WaitGroup) {
    defer wg.Done()
    ch <- fmt.Sprintf("doSomething: %d", i)
    i++
    if i == 10 {
        return
    }
    wg.Add(1)
    go doSomething(ch, wg)
}

func main() {
    ch := make(chan string)
    var wg sync.WaitGroup
    wg.Add(1)
    go doSomething(ch, &wg)
    go func() {
        wg.Wait()
        close(ch)
    }()
    for s := range ch {
        fmt.Println(s)
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

一个通道有一个接收者和未知数量的 goroutine 发送者导致死锁 的相关文章

随机推荐