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

时间:2015-11-08 02:10:09

标签: go channel goroutine

以下代码会产生错误原因?

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

一个值被发送到该频道,并在下一行中被接收。从技术上讲它应该有用。

2 个答案:

答案 0 :(得分:4)

频道可以缓冲无缓冲。缓冲通道可以在其内部存储多个项目,但是当您向缓冲通道添加内容时,添加该项目的goroutine只能在另一个goroutine移除该项目时继续。没有地方“离开”该项目,它必须直接传递到另一个goroutine,并且第一个goroutine将等到另一个从该项目中取出该项目。

这是您的代码中发生的事情。使用make创建频道时,如果未指定容量作为第二个参数,则会获得无缓冲的频道。要创建缓冲通道,请将第二个参数传递给makee.g

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

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

答案 1 :(得分:0)

我现在已经学到了很多关于频道的知识,现在我能够回答这个问题了。

在第16行,当消息&#34; test&#34;由主线程(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的流/执行暂停,直到从另一个goroutine中的同一通道接收数据。