【问题标题】:Why does this code generate an error?为什么这段代码会产生错误?
【发布时间】:2016-02-08 23:15:06
【问题描述】:

下面这段代码为什么会报错?

func main() {

    messages := make(chan string)

    messages <- "test" //line 16

    fmt.Println(<-messages)

}

产生以下错误。

fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
    /tmp/sandbox994400718/main.go:16 +0x80

一个值被发送到通道,并在下一行被接收。从技术上讲,它应该可以工作。

【问题讨论】:

    标签: go channel goroutine


    【解决方案1】:

    频道可以是缓冲的无缓冲的。缓冲通道可以在其“内部”存储许多项目,但是当您向缓冲通道添加某些内容时,只有在另一个 goroutine 删除该项目时,才会继续添加项目。没有地方可以“离开” item,它必须直接传递给另一个 goroutine,第一个 goroutine 会等到另一个 goroutine 从中取走 item。

    这就是您的代码中发生的情况。当您使用make 创建通道时,如果您没有将容量指定为第二个参数,您将获得一个无缓冲通道。要创建缓冲通道,请将第二个参数传递给 makee.g

    messages := make(chan string, 1) // could be larger than 1 if you want
    

    这允许 goroutine 将项目(在这种情况下为 string)添加到通道,当另一个 goroutine 将来尝试从通道获取项目时,它将可用,然后原始 goroutine 可以继续处理。

    【讨论】:

    • 我明白了,但是这个例子play.golang.org/p/2ox5ObgKIP 怎么不需要缓冲区。
    • @nJoshi 在该示例中有 两个 goroutine。以调用 go func() ... 开始的 goroutine 将字符串传递到通道(并等待),主 goroutine 检索它(并允许另一个继续)。
    【解决方案2】:

    我现在已经了解了很多关于频道的知识,现在我可以回答这个问题了。

    在第 16 行,当消息“test”被主线程(goroutine)发送到通道时,执行暂停,运行时会寻找其他的 goroutines准备好接收来自通道消息的值。由于没有其他通道,运行时会引发死锁消息的恐慌。这是一个典型的死锁例子。

    要解决这个问题,可以做两件事。

    1) 按照 Matt 的建议使用缓冲通道(答案之一)。

    2) Else 在 go 例程中具有发送到通道或从通道接收的语句。

    func main() {
    
        messages := make(chan string)
    
        go func() {
            messages <- "test" //line 16
        }()
        fmt.Println(<-messages)
    
    }
    

    所以最重要的一点是,

    1) 通道只能用于 goroutine 之间的通信,即当您在一个 goroutine 中发送到通道时,您只能在另一个不同的 goroutine 中接收它。

    2) 当数据被发送到 goroutine 中的通道时,该 goroutine 的流程/执行会暂停,直到从另一个 goroutine 中的同一通道接收到数据。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-23
      • 1970-01-01
      • 2018-04-19
      • 1970-01-01
      • 1970-01-01
      • 2011-01-27
      相关资源
      最近更新 更多