首页 > 解决方案 > 为什么 goroutines 用缓冲通道解决死锁问题?

问题描述

我有一个缓冲通道,我故意限制为 2 个元素。当我将更多元素写入通道而不从中读取时,我会按预期出现死锁。但是,如果我使用 goroutine 写入我的频道,问题就消失了。为什么?

// Function to process messages in an array. We stop processing once we
// encounter the string 'stop' even if there are other messages
func processCmd(s []string, c chan int) {

    msgCount := 0

    for index, v := range s {

        if index == len(s)-1 && v == "stop" {
            // If we've reached the last element and the message is "stop", don't count it
            break
        } else if v == "stop" {
            c <- msgCount // Send msgCount to the channel
            continue
        } else {
            msgCount++
        }
    }

    c <- msgCount // Send msgCount to the channel

    close(c)
}

func main() {
    s := []string{"message a", "message b", "message c", "stop", "message d", "stop", "message e"}

    c := make(chan int, 2)

    processCmd(s, c)
    //go processCmd(s, c) // doesn't have an issue with buffer length

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

}

标签: gogoroutine

解决方案


内联运行时processCmd(如代码所示),没有从通道接收任何内容。一旦添加了两个元素,processCmd就会等到有空间添加更多元素。正如您所说,这按预期工作。

在 goroutine 中运行processCmd时,main()启动 goroutine 并进入for v := range c循环。这将消耗项目,c直到通道关闭。一旦v := range c消耗了第一个元素,processCmd就可以自由地向通道添加更多数据,从而解除阻塞。

这将一直持续到processCmd关闭通道,此时 for 循环将终止,程序也将终止。

注意:为了可见性,不要忘记添加go标签。goroutine看标签的人不多。


推荐阅读