我正在尝试编写一个简单的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个独立的通道来计算子和。两个渠道如何依赖?
答案 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
将无法完成,因为它需要首先将其提供给该代码!