英文:
The following golang code deadlocks. Could someone help in understanding why?
问题
这个例子是从http://blog.golang.org/pipelines中提取的。它可以运行并给出正确的答案,但会显示以下运行时错误:"fatal error: all goroutines are asleep - deadlock!"。有人可以帮我理解为什么会发生这种情况吗?
package main
import (
"fmt"
)
func gen(nums ...int) <-chan int {
out := make(chan int)
go func() {
for _, n := range nums {
out <- n
}
}()
return out
}
func sq(in <-chan int) <-chan int {
out := make(chan int)
go func() {
for n := range in {
out <- n * n
}
close(out)
}()
return out
}
func main() {
for n := range sq(gen(2, 3)) {
fmt.Println(n)
}
}
然而,以下修改不会出现这种情况。
func main() {
// 设置管道。
c := gen(2, 3)
out := sq(c)
// 消费输出。
fmt.Println(<-out) // 4
fmt.Println(<-out) // 9
}
英文:
This example is taken from http://blog.golang.org/pipelines. It runs and gives correct answer but it shows following runtime error: "fatal error: all goroutines are asleep - deadlock!". Could anyone help me understand why this is happening?
package main
import (
"fmt"
)
func gen(nums ...int) <- chan int {
out := make(chan int)
go func() {
for _, n := range nums {
out <- n
}
}()
return out
}
func sq(in <- chan int) <- chan int {
out := make(chan int)
go func() {
for n := range in {
out <- n * n
}
close(out)
}()
return out
}
func main() {
for n := range sq(gen(2,3)) {
fmt.Println(n)
}
}
However the following modification doesn't.
func main() {
// Set up the pipeline.
c := gen(2, 3)
out := sq(c)
// Consume the output.
fmt.Println(<-out) // 4
fmt.Println(<-out) // 9
}
答案1
得分: 2
sq()
函数中的for n := range in
永远不会退出,并且在读取了2个值后开始阻塞,因为gen()
从未关闭其通道。
在gen()
的go func
中添加close(out)
将使其正常工作:请参见playground。
使用通道时,接收器会阻塞,直到接收到一个值。
当与通道一起使用时,range关键字将在通道关闭之前一直等待。
sq()
被阻塞,这意味着close(out)
从未被调用,进而main()
在range sq()
上阻塞(因为通道sq
没有关闭)。
在您的第二个示例中,main()
本身退出,这意味着即使sq()
被阻塞,一切仍然停止。
英文:
The for n := range in
of the sq()
function never exits, and start blocking (after reading 2 values), because gen()
never closed its channel.
Adding close(out)
to the go func
of gen()
would make it work: see playground.
With channel, the receiver blocks until receiving a value.
The range keyword, when used with a channel, will wait on the channel until it is closed.
sq()
is blocked, which means close(out)
is never called, and in turn main()
blocks on range sq()
(since the channel sq
isn't closed).
In your second example, main()
itself exits, which means even though sq()
is blocked, everything still stops.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论