Go の同時実行モデルでは、select はゴルーチンが複数の処理を待機できるようにする強力な構造です。チャンネルを同時に操作します。ただし、選択ケース内でチャネル操作を連鎖させようとすると、予期せぬ動作や潜在的なデッドロックにつながる可能性があるため、一般的な落とし穴が発生します。
2 つのチャネル (A と B) を多重化しようとする次のコード スニペットを考えてみましょう。 ) select:
func main() { ch := fanIn(talk("A", 10), talk("B", 1000)) for i := 0; i < 10; i++ { fmt.Printf("%q\n", <-ch) } }
を使用して、さまざまな時間遅延を設定します。この例では、talk は、指定された遅延で一連のメッセージを送信するチャネルを返します。 fanIn は、select ステートメントを使用して input1 と input2 の両方から値を受け取る新しいチャネルを作成するヘルパー関数です。
select case ステートメントが次のように変更されると、
select { case ch <- <-input1: case ch <- <-input2: }
an予期せぬ結果が発生します。一部の値がドロップされ、最終的にはファンイン チャネルがそれ以上値を受信できなくなるため、デッドロックが発生します。
この動作を理解するには、ブロック操作と非ブロック操作の概念を理解することが重要です。選択します。 select ステートメントでは、常に 1 つのチャネル読み取りまたは書き込み操作のみがノンブロッキングです。他のすべての操作は通常どおりに動作します。
変更された選択ケースでは、チャネル受信操作 (
この非ブロック動作の結果、最初の受信操作が成功したとき (例: <-input1 から)、次のものが読み取られます。そして値を保存します。ただし、後続の ch
その結果、値が削除され、観察されたデッドロックにつながります。
正しい動作をするには、次のことを確認してください。選択されたケースにおける最後の送信または受信操作のみが非ブロッキングであること。つまり、中間の受信操作には、矢印演算子 <- の代わりに代入演算子 := を使用します。
select { case t := <-input1: ch <- t case t := <-input2: ch <- t }
このように選択ケースを調整することで、チャネル操作が適切に連鎖され、すべての値が値の欠落やデッドロックのリスクがなく、正しく送受信されます。
以上がGo の「select」ステートメントでのチェーンされたチャネル操作は、ブロック動作と非ブロック動作にどのように影響しますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。