この記事では、php エディターの Xiaoxin が、Go プログラムに関する重要な問題、つまり goroutine の作業が完了する前に終了する状況について紹介します。 Go 言語では、ゴルーチンはタスクを同時に実行できる軽量のスレッドです。ただし、ゴルーチンの作業が完了する前にプログラムが終了する可能性がある場合、プログラムがタスクを正しく完了できるように、この状況を処理する方法を理解する必要があります。次のコンテンツでは、この問題を調査し、それを解決するためのいくつかのソリューションを提供します。
チャンネルを適切にブロックして閉じる方法がわかりません。任意の数のワーカーを開始しているのですが、メイン関数がワーカーが完了する前に終了するか、チャネルが閉じられていないためにハングすることがわかりました。ワーカーがメイン チャネルを終了せずにチャネルを読み取るのを停止し、終了したら正常にチャネルを閉じてループを終了する、より良い方法が必要です。私が試みてもデッドロックに終わります。
待機グループの使用など、いくつかのことを試しましたが、問題は解決しません。 time.sleep
を追加するとプログラムは期待どおりに動作しますが、コメントアウトすると何も行われないことに気付きました。
これは、sleep
を保持する実行可能なサンプル https://go.dev/play/p/qhqnj-ajqbi です。これは、スリープ タイムアウトがコメント化された壊れたコードです。
また、defer wg.done()
を worker()
関数内に移動しようとしましたが、同じ問題であり、スリープなしでは機能しません。
私は間違ったパラダイムを選択したのでしょうか、それとも単に間違ったパラダイムを使用しているだけなのでしょうか?
私は最初に「コードを機能させるためにコードを少し調整できますか? それともこの問題を再考する必要がありますか? 」と質問しました。その答えは次のとおりです。はい、小さな調整があることがわかりました。
チャネルに関する興味深い基本概念を学ぶ必要がありました。閉じたチャネルからデータを読み取ることができる、つまりチャネルをドレインすることができます。元の例で述べたように、チャンネルを閉じるのに適した場所が見つからないため、range
は終了しません。また、他の創造的な方法で強制的にチャンネルを強制した場合でも、プログラムの動作が悪くなります。
real」コードの微妙な違いによるもので、チャネル コンテンツ の処理に必要な時間は、# のデータを設定するのに必要な時間よりも長くなります。 ## チャンネルとモノが同期していません。 送信側でチャネルを閉じるための明確で実用的な方法がないため (チャネル チュートリアルの 99% で推奨されています)、複数のワーカーがチャネルを読んでいて、ワーカーがそのことを知らない場合、実際には最後の値が読み取られる main の goroutine を使用してこれを行うことは許容されます。
###解決###ワーカーを独自の
sync.waitgroup を使用して プログラムの終了をブロックしました。送信するデータがなくなったら、チャネルを独立して
close()
します、つまり、ライターが独自の待機グループを使用して終了するのを待ってブロックします。範囲ループの終了ケースは、チャネルのデフォルト値が返されるとき、つまり、チャネルの終わりに到達したときに eof タイプに達すると終了するためです。ブロッキング ランデブー チャネルは、閉じられるまでエンドポイントを持ちません。
これに対する私の見解は、並列にプッシュされる値の数がわからない場合、バッファリングされていないチャネルはスコープ内にあるため、そのチャネルを閉じるまで go はそのチャネルの長さを知る方法がありません。 。 。閉じられているため、終了値または最後まで残っているものを読み取ることを意味します。 workers.wait() は完了するまでブロックされます。
//m.sbmmt.com/link/2bf0ccdbb4d3ebbcb990af74bd78c658
クローズドチャネルの読み取り例
//m.sbmmt.com/link/d5397f1497b5cdaad7253fdc92db610b
###出力### リーリー
以上がgoroutine の作業が完了する前に Go プログラムが終了するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。