2012-12-27 110 views
1

我想编写一个简单的脚本去计算自然数之和高达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个独立的通道来计算子和。这两个通道如何依赖?

+1

想想当你通过频道发送某些内容时,你要向谁发送内容。请记住,您的频道是无缓冲的,所以通过频道发送会阻止,直到有人从该频道读取。 – nos

+0

http://play.golang.org/p/xyW_KfsFv7或http://play.golang.org/p/Ni-vmvKg2K – rputikar

+0

谢谢!因此,如果没有'go'语句,我将数据从一个线程发送到它自己。线程在从通话返回之前等待自己接收以便将数据发送到通道中? – dangerChihuahua007

回答

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

我没有使用过转了一会儿,所以这可能并非如此,但我记得你需要什么go再弄够程启动,因此:

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

如果sum不在另一个goroutine上运行,它试图执行:

c <- sum 

但没有什么读c;读取的代码c尚未达到,因为它正在等待sum完成,并且sum无法完成,因为它需要首先将其提供给该代码!

6

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

一种选择是向缓冲器添加到信道,所以可以写一个值到信道没有它阻断:

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

或者,如果运行sum()功能作为一个单独的goroutine,那么它可以阻止您的main()功能继续从通道读取的位置。