英文:
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
在这段代码中,一个值被发送到通道,然后在下一行被接收。从技术上讲,它应该可以工作。
英文:
The below piece of code generates an error why?
func main() {
messages := make(chan string)
messages <- "test" //line 16
fmt.Println(<-messages)
}
Generates the below error.
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
/tmp/sandbox994400718/main.go:16 +0x80
A value is sent to the channel, and in the next line it's being received. Technically it should work.
答案1
得分: 4
通道可以是“缓冲的”或“非缓冲的”。缓冲通道可以在内部存储多个项目,但是当你向缓冲通道添加项目时,只有当另一个goroutine移除该项目时,添加项目的goroutine才能继续执行。没有地方可以“留下”该项目,它必须直接传递给另一个goroutine,而第一个goroutine将等待直到另一个goroutine从中取走该项目。
这就是你的代码中发生的情况。当你使用make
创建一个通道时,如果不在第二个参数中指定容量,你将得到一个非缓冲通道。要创建一个缓冲通道,请向make
传递第二个参数,例如:
messages := make(chan string, 1) // 如果需要,可以大于1
这允许goroutine将项目(在本例中为string
)添加到通道中,在将来另一个goroutine尝试从通道获取项目时,该项目将可用,并且原始的goroutine可以继续处理。
英文:
Channels can be buffered or unbuffered. A buffered channel can store a number of items “inside” it, but when you add something to a buffered channel the goroutine adding the item can only continue when another goroutine removes the item. There is no place to “leave” the item, it must be passed directly to the other goroutine, and the first goroutine will wait until another one take the item from it.
This is what is happening in your code. When you create a channel with make
, if you don’t specify a capacity as the second argument you get an unbuffered channel. To create a buffered channel pass a second argument to make
, e.g.
messages := make(chan string, 1) // could be larger than 1 if you want
This allows the goroutine to add the item (a string
in this case) to the channel, where it will be available when another goroutine tries to get an item from the channel in the future, and the original goroutine can then continue processing.
答案2
得分: 0
我现在已经学到了很多关于通道的知识,现在我能够回答这个问题。
在第16行,当主线程(goroutine)向通道发送消息“test”时,执行会暂停,运行时会寻找其他准备好接收通道消息的goroutine。由于没有其他通道,运行时会引发死锁错误。这是一个经典的死锁示例。
要解决这个问题,有两件事可以做。
1)像Matt建议的那样使用带缓冲区的通道。
2)或者将发送到通道或从通道接收的语句放在一个goroutine中。
func main() {
messages := make(chan string)
go func() {
messages <- "test" //第16行
}()
fmt.Println(<-messages)
}
因此,从中可以得出以下要点:
1)通道只能用于在goroutine之间进行通信,即当你在一个goroutine中发送到通道时,只能在另一个goroutine中接收它,而不能在同一个goroutine中接收。
2)当在一个goroutine中向通道发送数据时,该goroutine的流程/执行将暂停,直到在另一个goroutine中从同一个通道接收到数据。
英文:
I have learnt a lot about channels now, and now I'm able to answer the question.
In line 16 when the message "test" is sent to the channel by the main thread(goroutine) the execution pauses and the runtime looks for other goroutines which are ready to receive the value from the channel message. Since there are no other channels the runtime raises a panic with the deadlock message. This a classic example for deadlock.
To fix this there are two things that can be done.
-
Use buffered channels as Matt suggested(one of the answers).
-
Else have the statement that sends to channel or receives from channel in a go routine.
func main() {
messages := make(chan string) go func() { messages <- "test" //line 16 }() fmt.Println(<-messages)
}
So the essential take aways from this is that,
-
Channels can be used only to communicate between goroutines i.e when you send to channel in one goroutine you can receive it only in another goroutine not the same.
-
When data is sent to a channel in a goroutine the flow/execution of that goroutine is paused until the data is received from the same channel in another goroutine.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论