2016-04-17 100 views
0

我正在學習頻道如何在Go中工作,並且偶然發現了關閉頻道的問題。這是的一個修改示例,它產生n-1個斐波納契數並通過通道發送它們,使通道容量的最後「元素」未被使用。關閉頻道

func fibonacci(n int, c chan int) { 
    x, y := 0, 1 
    for i := 0; i < n-1; i++ { 
     c <- x 
     x, y = y, x+y 

    } 
    // close(c) // It's commented out on purpose 
} 

func main() { 
    n := 10 
    c := make(chan int, n) 
    go fibonacci(n, c) 

    for i := 0; i < n; i++ { 
     _, ok := <-c 
     fmt.Println(ok) 
    } 
} 

的問題是,我得到:

fatal error: all goroutines are asleep - deadlock!

當我不關閉通道。究竟是什麼導致了僵局?爲什麼當我不關閉它時,我無法從容量邊界的頻道接收?

+1

如果您期望關閉某個通道,則讀取通道的習慣方式爲:for v:=範圍c {'因爲您不需要檢查確定 - 當通道關閉時,for循環將會退出。如果你不希望頻道關閉,請使用'for {select {case v:= < - c:...'。這樣你可以有額外的'case'條件,例如超時,監視取消令牌等等,並且在檢測到退出條件時打破for循環。 – eduncan911

回答

5

你寫了ň值進入通道(從0到n-1),但試圖從通道讀取n + 1值(從0到n)。在沒有明確關閉頻道的情況下,main函數將永遠等待最後一個值。

What exactly is causing the deadlock?

ñ迭代,運行fibonacci功能夠程將退出。在這個goroutine退出之後,你程序中唯一剩下的goroutine是main goroutine,而這個goroutine正在等待一些數據被寫入到c通道 - 而且因爲沒有其他goroutine可以將數據寫入這個頻道,它會永遠等待。這正是錯誤信息試圖告訴你的:「所有程序(」全部「只是」一個「,在這裏)都睡着了」

_, ok := <- c調用main函數只會在c通道關閉後立即停止阻塞(因爲從通道讀取被阻塞,這需要從另一個goroutine完成)。當通道關閉時,main函數將讀取通道中的剩餘數據(當它是緩衝通道時)

0

對於在通道主要預期N個通信循環,但只生產N-1在FUNC斐波納契

func fibonacci(n int, c chan int) { 
    x, y := 0, 1 
    for i := 0; i < n; i++ { //here 
     c <- x 
     x, y = y, x+y 

    } 
    // close(c) // It's commented out on purpose 
} 

應該工作 http://play.golang.org/p/zdRuy14f9x

+0

我知道,這也是爲了讓渠道容量的一個「元素」變成空的。 – syntagma

+0

但它造成了僵局。主要你永遠等待n的信息,因爲你不發送它。 – Uvelichitel