Go のデッドロック:「すべてのゴルーチンがスリープ状態」
ゴルーチンを使用する場合、デッドロックを回避するためにチャネル操作を効果的に管理することが重要です。これは、すべてのゴルーチンが無期限にブロックされ、デッドロック状況につながる場合に発生します。
コードを理解する
提供されたコードを調べてみましょう:
package main import ( "fmt" "sync" "time" ) type Item struct { name string } type Truck struct { Cargo []Item name string } func UnloadTrucks(c chan Truck) { for t := range c { fmt.Printf("%s has %d items in cargo: %s\n", t.name, len(t.Cargo), t.Cargo[0].name) } } func main() { trucks := make([]Truck, 2) ch := make(chan Truck) for i, _ := range trucks { trucks[i].name = fmt.Sprintf("Truck %d", i+1) fmt.Printf("Building %s\n", trucks[i].name) } for t := range trucks { go func(tr Truck) { itm := Item{} itm.name = "Groceries" fmt.Printf("Loading %s\n", tr.name) tr.Cargo = append(tr.Cargo, itm) ch <- tr }(trucks[t]) } time.Sleep(50 * time.Millisecond) fmt.Println("Unloading Trucks") UnloadTrucks(ch) fmt.Println("Done") }
このコードは、タイプ Truck のチャネル ch を作成し、食料品を積んだトラックをシミュレートする 2 つのゴルーチンを起動します。そしてそれらをチャンネルに送信します。次に、UnloadTrucks を呼び出して、トラックの内容を取得して出力します。
デッドロックの原因
問題は、ch チャネルを閉じるメカニズムがないことにあります。すべてのゴルーチンがトラックをチャネルに送信すると、UnloadTrucks にはループを終了する信号がありません。これは、ch が決して到着しない値をリッスンし続け、デッドロックが発生することを意味します。
解決策
デッドロックを解決するには、次の場合に ch チャネルを明示的に閉じる必要があります。ローディングゴルーチンが完了しました。 sync.WaitGroup を使用して、実行中の goroutine をカウントし、すべてが完了したらチャネルを閉じることができます。
var wg sync.WaitGroup go func() { wg.Wait() close(ch) }() UnloadTrucks(ch)
この変更により、すべての goroutine がトラックのロードを完了したら、UnloadTrucks が終了するようになります。 Wait 関数は、WaitGroup カウンタがゼロに達し、すべてのゴルーチンが作業を完了したことを示すまでブロックします。チャネルを閉じると、受信するトラックがもうないことが UnloadTrucks に通知され、ループを正常に終了できるようになります。
以上がすべてのゴルーチンがスリープしているときに Go でデッドロックを解決するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。