一尘不染

Go中的频道死锁

go

由于以下代码中的某种原因,我收到“致命错误:所有goroutine都在睡眠-死锁!”。我正在使用应该不阻塞的缓冲通道。不知道我在做什么错

package main

import (
    "fmt"
    "sync"
)

func main() {
    c := make(chan int, 2)
    var wg sync.WaitGroup
    wg.Add(2)

    go doSomething(c, wg)
    go doSomething(c, wg)
    go doSomething(c, wg)

    wg.Wait()

    close(c)

    for v := range c {
        fmt.Print(v)
    }

}

func doSomething(c chan<- int, wg sync.WaitGroup) {
    defer wg.Done()
    c <- 1

}

游乐场链接https://play.golang.org/p/J9meD5aKna


阅读 212

收藏
2020-07-02

共1个答案

一尘不染

虽然您的解决方案可能会起作用,但我对此并不满意。

首先,您需要更改通道大小以使其起作用这一事实表明存在潜在的问题/错误。现在,每次您要启动另一个时doSomething,都必须记住要更改通道的长度。

其次,您要等到所有goroutine完成后才能从通道读取。这是一种“浪费”,因为通道范围循环的要点之一是您不必等到所有项目生成(写入通道)后,就可以立即处理这些项目。他们已经准备好了。

所以我会像这样写你的代码

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

    var wg sync.WaitGroup
    wg.Add(3)
    go func() {
        doSomething(c)
        defer wg.Done()
    }()
    go func() {
        doSomething(c)
        defer wg.Done()
    }()
    go func() {
        doSomething(c)
        defer wg.Done()
    }()

    go func() {
        wg.Wait()
        defer close(c)
    }()

    for v := range c {
        fmt.Print(v)
    }
}

func doSomething(c chan<- int) {
    c <- 1
}

https://play.golang.org/p/T3dfiztKot

请注意,等待和关闭通道现在是如何在其自己的goroutine中进行的-这允许立即开始在通道上进行迭代(该通道现在没有缓冲!)。

我还更改了代码,以WaitGroup使它永远不会离开声明它的范围(即,它不用作参数),这是我个人的喜好。我相信它使代码更易于遵循和理解。

2020-07-02