为什么此代码会产生错误?

Why does this code generate an error?

为什么下面的代码会产生错误?

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

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

频道可以缓冲无缓冲。缓冲通道可以在其“内部”存储多个项目,但是当您向缓冲通道添加内容时,添加项目的 goroutine 只有在另一个 goroutine 删除项目时才能继续。没有地方可以“留下”物品,它必须直接传递给另一个 goroutine,第一个 goroutine 会等到另一个 goroutine 从它那里拿走物品。

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

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

这允许 goroutine 将项目(在本例中为 string)添加到频道,当另一个 goroutine 将来尝试从频道获取项目时,它将可用,并且原来的 goroutine 可以继续处理。

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

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

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

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

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

func main() {

    messages := make(chan string)

    go func() {
        messages <- "test" //line 16
    }()
    fmt.Println(<-messages)

}

所以最重要的是,

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

2) 当数据发送到 goroutine 中的通道时,该 goroutine 的 flow/execution 暂停,直到数据从另一个 goroutine 中的同一通道接收到。