WaitGroup と Channel を使用した Go のデッドロック
Go では、2 つ以上のゴルーチンが他方のゴルーチンの終了を無期限に待機すると、デッドロックが発生します。この例では、チャネル バッファーの不足と、WaitGroup を使用したゴルーチンの不適切な同期によって引き起こされるデッドロックの問題を調べます。
コード
<code class="go">package main import "fmt" import "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 return }() } wg.Wait() for c := range ch { fmt.Printf("c is %v", c) } }</code>
問題
このコードは、サイズ 4 のバッファーされたチャネルを介して 5 つの値を送信しようとします。ただし、チャネルがいっぱいになると、受信者が使用可能になるまでブロックされます。送信中のすべてのゴルーチンが終了したため、チャネルから受信できるゴルーチンはありません。
さらに、チャネル上に範囲を設定するゴルーチン (c := range ch の場合) も、より多くの値を期待しているため、無期限にブロックされたままになります。それ以上送信されていないにもかかわらずチャネルに到着すること。これにより、送信者と受信者の両方がお互いを待機するデッドロックが発生します。
解決策 1: チャネル バッファーを増やして閉じる
デッドロックを回避する 1 つの解決策は、次のとおりです。チャネル バッファ サイズを送信ゴルーチンの数以上の値に増やします。さらに、すべての送信が完了した後、チャネルを閉じる必要があります。これは、これ以上値を受信しないことを示します。
<code class="go">ch := make(chan []int, 5) ... wg.Wait() close(ch)</code>
解決策 2: Goroutine の受信で Done() を実行する
もう 1 つの解決策は、main 関数ではなく受信ゴルーチンで Done() を実行することです。そうすることで、値がゴルーチンによって受信されて消費されるまで、WaitGroup はデクリメントされません:
<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 return }() } go func() { for c := range ch { fmt.Printf("c is %v\n", c) wg.Done() } }() wg.Wait() }</code>
以上がWaitGroup とバッファーが制限されているチャネルを使用する場合、Go でデッドロックを回避するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。