2017-08-24 10 views
1
package main 

import (
    "fmt" 
    "time" 
) 

func main() { 
    p := producer() 
    for c := range p { 
     fmt.Println(c) 
    } 
} 

func producer() <-chan string { 
    ch := make(chan string) 
    go func() { 
     for i := 0; i < 5; i++ { 
      ch <- fmt.Sprint("hello", i) 
      time.Sleep(1 * time.Second) 
     } 
     // commented the below to show the issue 
     // close(ch) 
    }() 
    return ch 
} 

上記のコードを実行すると5つのメッセージが表示され、「すべてのgoルーチンはスリープデッドロックエラーです」というメッセージが表示されます。チャンネルを閉じるとエラーが消えてしまうことが分かります。goチャネルデッドロック

私が理解したいことは、コードがチャネル上で無限に待機し、チャネルにデータを送信する何もないことをランタイムがどのように認識するのかということです。

main()関数に追加のgoルーチンを追加すると、エラーは発生せず、チャネルで待機し続けます。

go func() { 
     for { 
      time.Sleep(2 * time.Millisecond) 
     } 
    }() 

だから、これは行くランタイムがちょうど潜在的にチャネルにデータを送信するので、デッドロックエラーを投げることができませんでしたランニングゴールーチンの存在を探しています。..意味するのでしょうか?

答えて

3

チャネルとmutex操作ですべてのゴルーチンがブロックされていると、 "すべてのgoルーチンがスリープデッドロックエラーです"というエラーが発生します。

スリーピングゴルーチンは、これらの操作のいずれかでブロックしません。デッドロックがなく、したがってパニックもありません。

4

あなたはGoはデッドロックの検出を実装する方法にいくつかのより多くの洞察をしたい場合は、"all goroutines are asleep - deadlock!"を投げるコード内の場所を見て:https://github.com/golang/go/blob/master/src/runtime/proc.go#L3751

のGoランタイムがどのようにいくつかの非常に単純な会計処理を続けるように見えます多くのゴルーチン、アイドルの数、ロックのために眠っている人の数(チャンネルI/O上のどの睡眠が増加するかわからない)。いつでも(ランタイムの残りの部分でシリアライズされています)、それはちょうど算術演算を行い、all - idle - locked > 0なら...もしそうなら、プログラムはまだ進歩するかもしれません...もし0なら、デッドロックしています。

無限ループでゴルーチンが眠ってしまうのを防ぐことができます(実験で行ったことと同じように、タイマーのためにスリープ状態になっているのはランタイムによって同じように扱われない可能性があります)。この場合、ランタイムはデッドロックを検出できず、永遠に実行できません。

また、実行時にデッドロックが発生しているかどうかは確かではありません。興味のある人は、checkdead()と呼んでいる人をさらに調べることができます。

はDISCLAIMER-私はちょうどについては

+0

おかげ@Eddy R :-)テレビで1を再生し、囲碁コア開発者ではありませんよ。 +1を与えようとしましたが、私の低い点のためにシステムが許可しませんでした。 – tblogger