登录
首页 >  Golang >  Go问答

通道和等待组进入死锁

来源:stackoverflow

时间:2024-03-12 17:24:28 129浏览 收藏

“纵有疾风来,人生不言弃”,这句话送给正在学习Golang的朋友们,也希望在阅读本文《通道和等待组进入死锁》后,能够真的帮助到大家。我也会在后续的文章中,陆续更新Golang相关的技术文章,有好的建议欢迎大家在评论留言,非常感谢!

问题内容

我在整理 go 例程并让它们与主 go 例程上的通道进行通信时遇到了麻烦。为了简化,我的代码如下所示:

func main() {
    channel := make(chan string)
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go performTest(channel, &wg, i)
    }

    wg.Wait()
    close(channel)

    for line := range channel {
        fmt.Print(line)
    }
}

func performTest(channel chan string, wg *sync.WaitGroup, i int) {
     defer wg.Done()
     // perform some work here
     result := fmt.sprintf("Pretend result %d", i)
     channel <- result
}

这似乎陷入了某种僵局,但我不明白为什么。它卡在 wg.wait() 上,尽管我希望一旦所有 goroutine 在等待组上调用 done 后它就会继续。我在这里缺少什么?我想等待 goroutine,然后迭代通道中的所有结果。


正确答案


您可以在单独的 go 例程中等待该组并关闭通道。如果通道关闭,则您在通道上的范围将在收到最后发送的值后结束。

如果您只是等待,则不会从频道收到任何信息。由于通道是无缓冲的,因此 performtest goroutine 将无法发送。对于无缓冲的通道,发送操作将阻塞,直到收到为止。因此,延迟的 wg.done 调用永远不会发生,并且您的程序陷入僵局。由于 done 仅在执行永远阻塞发送后才被调用。

func main() {
    channel := make(chan string)
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go performTest(channel, &wg, i)
    }
    
    // this is the trick
    go func() {
        wg.Wait()
        close(channel)
    }()

    for line := range channel {
        fmt.Print(line)
    }
}

func performTest(channel chan string, wg *sync.WaitGroup, i int) {
    defer wg.Done()
    // perform some work here
    result := fmt.Sprintf("Pretend result %d\n", i)
    channel <- result
}

https://play.golang.com/p/5pACJzwL4Hi

今天关于《通道和等待组进入死锁》的内容介绍就到此结束,如果有什么疑问或者建议,可以在golang学习网公众号下多多回复交流;文中若有不正之处,也希望回复留言以告知!

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>