【问题标题】:One channel with one receiver and unknown number of goroutines senders causing deadlock一个通道,一个接收者,未知数量的 goroutines 发送者导致死锁
【发布时间】:2019-06-07 13:01:57
【问题描述】:

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

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

我尝试过使用 WaitGroup,问题是,我读到我不能在 goroutine 中使用 Add,我应该在主进程/goroutine 中使用 wg.Add(1),我已经尝试过在父 goroutine 中使用 Add 生成子 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 一起工作,并在它们完成后关闭通道。

【问题讨论】:

    标签: go deadlock channel goroutine


    【解决方案1】:

    有几个问题。

    首先是程序在将等待组值作为参数传递时复制它们。复制时等待组无法正常工作。而是将指针传递给等待组。

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

    第三个问题是通道上的主要范围,但没有关闭通道。 Main 不会因此退出。

    要解决第二个和第三个问题,请启动另一个 goroutine 等待 doSomthings 并在完成后关闭通道。

    试试这个:

    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)
        }
    }
    

    【讨论】:

    • 我在全球化 'wg' 之前尝试过,它导致了死锁,我猜这是因为第二个和第三个问题。我现在明白了,谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-07
    • 1970-01-01
    相关资源
    最近更新 更多