The following golang code deadlocks. Could someone help in understanding why?

huangapple go评论80阅读模式
英文:

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 (
	&quot;fmt&quot;
)

func gen(nums ...int) &lt;- chan int {
	out := make(chan int)
	go func() {
		for _, n := range nums {
			out &lt;- n
		}
	}()
	return out
}

func sq(in &lt;- chan int) &lt;- chan int {
	out := make(chan int)
	go func() {
		for n := range in {
			out &lt;- 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(&lt;-out) // 4
    fmt.Println(&lt;-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.

huangapple
  • 本文由 发表于 2014年10月4日 12:03:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/26189485.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定