为什么我的频道陷入困境?

时间:2012-12-27 06:55:07

标签: go

我正在尝试编写一个简单的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

为什么我的代码会死锁?我很困惑,因为我使用2个独立的通道来计算子和。两个渠道如何依赖?

3 个答案:

答案 0 :(得分:6)

您的频道是无缓冲的,因此c <- sum中的sum()行将会阻止,直到另一端的其他例程读取为止。

一个选项是向通道添加缓冲区,因此您可以在不阻塞的情况下将值写入通道:

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

或者,如果您将sum()函数作为单独的goroutine运行,那么当main()函数继续从通道读取时,它可以阻塞。

答案 1 :(得分: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)

添加频道缓存。

答案 2 :(得分: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将无法完成,因为它需要首先将其提供给该代码!