2012-12-27 107 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()功能繼續從通道讀取的位置。