2016-07-02 7 views
3

3つのゴルーチンのチェーンを設定しています。それぞれの入力には出力チャンネルがあります。 goroutinesは入力チャンネルから読み込み、終了し、値をインクリメントし、出力チャンネルに送ります。しかし、この出力とデッドロック以下のプログラム:なぜこのGoプログラムはハングアップしますか?

goroutine 'one': 1 
goroutine 'two': 2 
goroutine 'three': 3 
goroutine 'one': 10 
goroutine 'two': 11 
goroutine 'one': 100 
fatal error: all goroutines are asleep - deadlock! 

コード:出力チャンネルからの読み込みループは到達しませんので

package main 

import (
    "fmt" 
) 

func int_channel(id string, i chan int, o chan int) { 
    defer close(o) 

    for x := range i { 
    fmt.Printf("goroutine '%s': %d\n", id, x) 
    o <- x + 1 
    } 

    fmt.Println("done") 
} 

func main() { 
    c0 := make(chan int) 
    c1 := make(chan int) 
    c2 := make(chan int) 
    c3 := make(chan int) 

    go int_channel("one", c0, c1) 
    go int_channel("two", c1, c2) 
    go int_channel("three", c2, c3) 

    c0 <- 1 
    c0 <- 10 
    c0 <- 100 
    c0 <- 1000 
    c0 <- 10000 
    c0 <- 100000 
    close(c0) 

    fmt.Println("Sent all numbers to c0") 

    for x := range c3 { 
    fmt.Printf("out: %d\n", x) 
    } 
} 

答えて

4

それは、このようにチャネルが「emptyed」されていませんがハングし、一度各チャネルに値が書き込まれると、進捗が行われず、プログラムがハングすることがあります。すなわち

func main() { 
    c0 := make(chan int) 
    c1 := make(chan int) 
    c2 := make(chan int) 
    c3 := make(chan int) 

    go int_channel("one", c0, c1) 
    go int_channel("two", c1, c2) 
    go int_channel("three", c2, c3) 

    go func(){ 
    c0 <- 1 
    c0 <- 10 
    c0 <- 100 
    c0 <- 1000 
    c0 <- 10000 
    c0 <- 100000 
    fmt.Println("Sent all numbers to c0") 
    close(c0) 
    }() 


    for x := range c3 { 
    fmt.Printf("out: %d\n", x) 
    } 
} 

、それは別のゴルーチン入力に書き込み固定するIOW、ラインc0 <- 1が実行されると、値はthroughtすべての3つのCANNELSを流れ、c3で終わるが、リーダループはまだ達していないので、それはちょうど "そこに座っている"。その後、c0 <- 10という行が実行され、に書き込むことができないため、この値はc2になります。前回の値はまだ書き込みをブロックしています。したがって、行c0 <- 100が実行されると、すべてのチャネルがいっぱいになり、それ以上進行することはできません。

+0

まだ明らかになっているようです:)まだGoの並行性モデルに慣れています。ありがとう! –

+0

もう一つの方法は、 'c0'をバッファされたチャンネルにして、あなたの初期の"データの詰め込み "をすべて受け入れるようにすることです。 – Vatine

1

あなたはc3から適時に読んでいません。あなたはあまりにも多くの値をc0に送り込んでいます。 、

send 1 on c0 => recv 1 on c1 => send 2 on c2 => 
     recv 2 on c2 => send 3 on c3 => recv 3 on c3 

send 10 on c0 => recv 10 on c1 => send 11 on c2 => 
     recv 11 on c2 => send 12 on c3 -- // c3 still hasn't been read 
              // from and so send 
              // operation blocks here. 

C0、C1、すべてが彼らの最終的にブロックを送信するまで受信し続けるC2:だから、チャンネル間の通信は、次のように起こります。 @ ainの答えは以下の解決策を参照することができます。

関連する問題