我有一个缓冲通道,有意限制为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)
    }

}

最佳答案

内联运行processCmd时(如代码所示),该通道没有任何内容可接收。一旦添加了两个元素,processCmd将只等到有空间添加更多元素。如您所说,这按预期工作。
在goroutine中运行processCmd时,main()启动goroutine并进入for v := range c循环。这将消耗c中的项目,直到关闭通道。一旦v := range c消耗了第一个元素,processCmd便可以自由地向通道添加更多数据,从而对其进行解锁。
这将一直持续到processCmd关闭通道为止,此时for循环将终止,程序也将终止。
注意:为了获得可见性,请不要忘记添加go标签。观看goroutine标签的人并不多。

10-06 04:36