Golang では、チャネルはコルーチン間でデータを安全に受け渡すことができる非常に便利なデータ構造です。チャネルを閉じて、すべてのデータが配信されたことを受信者に知らせることができます。ただし、場合によっては、チャネルを閉じない方が良い選択肢になる場合があります。
まず、チャネルを閉じることがなぜ役立つのかを見てみましょう。データをチャネルに送信すると、複数のコルーチンが同時にそのデータをリッスンする可能性があります。ここに簡単な例があります:
c := make(chan int) go func() { for i := 0; i < 10; i++ { c <- i } }() go func() { for i := range c { fmt.Println(i) } }()
ここでは、整数型のチャネルを作成し、2 つのコルーチンを開始します。 1 つのコルーチンは 0 から 9 までの数字をチャネルに送信し、もう 1 つのコルーチンはデータを受信するとそのデータを出力します。
送信者が送信を完了したら、受信者がすべてのデータが送信されたことを認識できるようにチャネルを閉じる必要があります。これは、送信コルーチンが送信を終了したときに close(c)
を呼び出すことで実現できます。
しかし、コルーチンがすべてのデータを受信できない場合はどうなるでしょうか?ハングしているか閉じられている可能性があります。この場合、送信者がチャネルを閉じると、受信者がパニックを起こし、プログラムがクラッシュする可能性があります。
この問題の解決策は、送信側にロックを追加し、受信側のコルーチンが完了したときにロックを解放することです。ただし、このアプローチではコードがより複雑になり、パフォーマンスが低下する可能性があります。
もっと良い方法があります。チャネルを閉じるのではなく、Go 言語の機能を使用して、すべてのデータが送信されたことを示す追加要素をチャネルに送信します。この要素は任意のタイプにすることができますが、通常は nil または特定のタグを使用します。
サンプル コードを変更する方法は次のとおりです。
c := make(chan int) done := make(chan struct{}) go func() { for i := 0; i < 10; i++ { c <- i } done <- struct{}{} }() go func() { for { select { case i := <-c: fmt.Println(i) case <-done: return } } }()
ここでは、チャネル done
を作成し、送信者が構造体の送信を完了したときにチャネルに送信します。レシーバーのコルーチンは、select
ステートメントを使用して 2 つのチャネルをリッスンします。チャネル done
から信号を受信すると、終了します。これにより、すべてのデータが送信されたことを受信者に伝える簡単な方法を提供しながら、チャネルが閉じるという問題が回避されます。
要約すると、チャンネルを閉じるとプログラムがクラッシュする可能性があるため、不要な問題が発生する可能性があります。場合によっては、チャネルを閉じない方が良い選択肢になる場合があります。すべてのデータが送信されたことを示すために、チャネル上で追加の要素を送信できます。このアプローチにより、ロックの必要性が回避され、プログラムがよりシンプルかつ効率的になります。
以上がgolang チャンネルは閉じられていませんの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。