WaitGroups を使用した Go 同時実行におけるデッドロックの検出
Go では、ゴルーチンを調整するためにチャネルと待機グループを使用して同時実行を管理することがよくあります。ただし、デッドロックにつながる可能性がある潜在的な落とし穴を理解することが重要です。
問題の説明
バッファーされたチャネルと待機グループを使用しようとする次のコードを考えてみましょう。
<code class="go">package main import ( "fmt" "sync" ) func main() { ch := make(chan []int, 4) var m []int var wg sync.WaitGroup for i := 0; i < 5; i++ { wg.Add(1) go func() { defer wg.Done() ch <- m // Send to channel return }() } wg.Wait() // Wait for all goroutines to complete for c := range ch { fmt.Printf("c is %v", c) // Iterate over channel } }</code>
容量に達するとチャネルが自動的に閉じることが期待されていたにもかかわらず、このコードは予期せずデッドロック エラーを引き起こします。
解決策
は 2 つあります。デッドロックにつながる主な問題:
デッドロックを解決するには、次の 2 つの解決策があります。
解決策 1: チャネル容量の拡張と明示的なクローズ
<code class="go">ch := make(chan []int, 5) // Increase channel capacity ... wg.Wait() close(ch) // Close the channel to stop range loop</code>
これにより、チャネル内に十分なスペースがあることが保証され、明示的にクローズされ、範囲ループが終了できるようになります。
解決策 2: ゴルーチンで完了条件を通知する
<code class="go">func main() { ch := make(chan []int, 4) var m []int var wg sync.WaitGroup for i := 0; i < 5; i++ { wg.Add(1) go func() { ch <- m wg.Done() // Signal completion within goroutine return }() } go func() { for c := range ch { fmt.Printf("c is %v\n", c) wg.Done() //Decrement count for each iteration } }() wg.Wait() }</code>
この解決策では、各ゴルーチンは、ゴルーチン自体内で wg.Done() を呼び出すことによって、その完了を通知します。 waitgroup も反復ごとに range ループ内でデクリメントされ、wg.Wait() が最終的に完了してプログラムが終了することが保証されます。
以上がGo で WaitGroups とバッファリングされたチャネルを使用すると、どのようにしてデッドロックが発生するのでしょうか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。