为什么我的通道死锁了?

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

Why are my channels deadlocking?

问题

我正在尝试编写一个简单的Go脚本,用于计算自然数的总和,直到8为止:

package main
import "fmt" 

func sum(nums []int, c chan int) {
    var sum int = 0
    for _, v := range nums {
        sum += v    
    }
    c <- sum
}

func main() {
    allNums := []int{1, 2, 3, 4, 5, 6, 7, 8}
    c1 := make(chan int)
    c2 := make(chan int)
    sum(allNums[:len(allNums)/2], c1)
    sum(allNums[len(allNums)/2:], c2)
    a := <- c1
    b := <- c2
    fmt.Printf("%d + %d is %d :D", a, b, a + b)
}

然而,运行此程序会产生以下输出。

throw: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.sum(0x44213af00, 0x800000004, 0x420fbaa0, 0x2f29f, 0x7aaa8, ...)
    main.go:9 +0x6e
main.main()
    main.go:16 +0xe6

goroutine 2 [syscall]:
created by runtime.main
    /usr/local/go/src/pkg/runtime/proc.c:221

exit status 2

为什么我的代码发生了死锁?我感到困惑,因为我使用了两个独立的通道来计算子总和。这两个通道有什么依赖关系吗?

英文:

I am trying to program a simple Go script that calculates the sum of the natural numbers up to 8:

package main
import &quot;fmt&quot; 

func sum(nums []int, c chan int) {
	var sum int = 0
	for _, v := range nums {
		sum += v	
	}
	c &lt;- sum
}

func main() {
	allNums := []int{1, 2, 3, 4, 5, 6, 7, 8}
	c1 := make(chan int)
	c2 := make(chan int)
	sum(allNums[:len(allNums)/2], c1)
	sum(allNums[len(allNums)/2:], c2)
	a := &lt;- c1
	b := &lt;- c2
	fmt.Printf(&quot;%d + %d is %d :D&quot;, a, b, a + b)
}

However, running this program produces the following output.

throw: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.sum(0x44213af00, 0x800000004, 0x420fbaa0, 0x2f29f, 0x7aaa8, ...)
    main.go:9 +0x6e
main.main()
    main.go:16 +0xe6

goroutine 2 [syscall]:
created by runtime.main
    /usr/local/go/src/pkg/runtime/proc.c:221

exit status 2

Why is my code deadlocking? I am confused because I am using 2 separate channels to calculate the sub-sums. How are the two channels dependent at all?

答案1

得分: 6

你的通道是无缓冲的,所以在sum()函数中的c &lt;- sum这一行会阻塞,直到其他协程从另一端读取。

一种选择是给通道添加缓冲区,这样你可以在不阻塞的情况下向通道写入值:

c1 := make(chan int, 1)
c2 := make(chan int, 1)

另外,如果你将sum()函数作为一个单独的goroutine运行,那么它可以在main()函数继续执行到从通道读取的地方时阻塞。

英文:

Your channels are unbuffered, so the c &lt;- sum line in sum() will block until some other routine reads from the other end.

One option would be to add buffers to the channels, so you can write a value to the channel without it blocking:

c1 := make(chan int, 1)
c2 := make(chan int, 1)

Alternatively, if you run the sum() function as a separate goroutine, then it can block while your main() function continues to the point where it reads from the channels.

答案2

得分: 5

是的,你需要像这样添加go

go sum(allNums[:len(allNums)/2], c1)

go sum(allNums[len(allNums)/2:], c2)

或者

c1 := make(chan int,1)
c2 := make(chan int,1)

添加通道缓存。

英文:

Yes, you need to add go like

go sum(allNums[:len(allNums)/2], c1)

go sum(allNums[len(allNums)/2:], c2)

or

c1 := make(chan int,1)
c2 := make(chan int,1)

add channel cache.

答案3

得分: 2

我已经有一段时间没有使用Go了,所以这可能不是这种情况,但根据我记得的,你需要使用go来启动另一个goroutine,所以:

go sum(allNums[:len(allNums)/2], c1)

go sum(allNums[len(allNums)/2:], c2)

如果sum没有在另一个goroutine上运行,它会尝试执行:

c <- sum

但是没有任何地方读取c;读取c的代码还没有被执行,因为它正在等待sum完成,而sum无法完成,因为它需要先将结果给那段代码!

英文:

I haven't used Go in a while, so this may not be the case, but from what I remember you need go to get another goroutine started, so:

go sum(allNums[:len(allNums)/2], c1)

go sum(allNums[len(allNums)/2:], c2)

If sum isn't running on another goroutine, it tries to execute:

c &lt;- sum

But nothing's reading c; the code reading c has not been reached yet because it's waiting for sum to finish, and sum won't finish because it needs to give it to that code first!

huangapple
  • 本文由 发表于 2012年12月27日 14:55:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/14050673.html
匿名

发表评论

匿名网友

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

确定