全チャンネル閉鎖時のselect文からの脱却
質問
2つのゴルーチンが独立してデータを生成し、それぞれをチャネルに送信しています。私のメインゴルーチンでは、これらの出力が来るとそれぞれを消費したいと思いますが、それらが入ってくる順序は気にしないでください。各チャンネルは、出力を使い切ったら自分自身を閉じます。select文はこのように独立して入力を消費するための最も良い構文ですが、両方のチャンネルが閉じるまでそれぞれをループさせる簡潔な方法を見たことがありません。
for {
select {
case p, ok := <-mins:
if ok {
fmt.Println("Min:", p) //consume output
}
case p, ok := <-maxs:
if ok {
fmt.Println("Max:", p) //consume output
}
//default: //can't guarantee this won't happen while channels are open
// break //ideally I would leave the infinite loop
//only when both channels are done
}
}
は、私が思いつく限りでは、次のようなものです(スケッチしただけなので、コンパイルエラーが出るかもしれません)。
for {
minDone, maxDone := false, false
select {
case p, ok := <-mins:
if ok {
fmt.Println("Min:", p) //consume output
} else {
minDone = true
}
case p, ok := <-maxs:
if ok {
fmt.Println("Max:", p) //consume output
} else {
maxDone = true
}
}
if (minDone && maxDone) {break}
}
しかし、これは2つか3つ以上のチャンネルで作業している場合、手に負えなくなりそうです。私が知っている唯一の他の方法は、switch 文でタイムアウトのケースを使用することですが、これは早期に終了するリスクを冒すには十分小さいか、最終ループにあまりにも多くのダウンタイムを注入することになります。selectステートメント内にあるチャンネルをテストするためのより良い方法はありますか?
どのように解決するのですか?
あなたの例の解決策はうまくいきません。一旦それらのうちの 1 つが閉じられると、それは常にすぐに通信可能な状態になります。これは、あなたのゴルーチンが決して降伏せず、他のチャネルが決して準備できないことを意味します。事実上、無限ループに入ることになります。この効果を説明するために、ここに例を掲載しました。 http://play.golang.org/p/rOjdvnji49
では、この問題をどのように解決すればよいのでしょうか。nil チャンネルは、決して通信の準備ができていません。したがって、閉じたチャネルに遭遇するたびに、そのチャネルをnilして、二度と選択されないようにすることができます。実行可能な例はこちらです。 http://play.golang.org/p/8lkV_Hffyj
for {
select {
case x, ok := <-ch:
fmt.Println("ch1", x, ok)
if !ok {
ch = nil
}
case x, ok := <-ch2:
fmt.Println("ch2", x, ok)
if !ok {
ch2 = nil
}
}
if ch == nil && ch2 == nil {
break
}
}
扱いにくくなることを恐れているのであれば、それはないと思います。一度に多くの場所にチャンネルが行くことは非常にまれです。これは非常にまれなことなので、私の最初の提案は、それに対処することです。10 個のチャンネルと nil を比較する長い if 文は、select で 10 個のチャンネルを処理しようとするときの最悪の部分ではありません。
関連
-
[解決済み] intをint64に変換するには?
-
[解決済み] response.Bodyを閉じないとどうなりますか?
-
[解決済み] reflectを使用して、構造体フィールドの値を設定するにはどうすればよいですか?
-
[解決済み] スライスを格納する interface{} 上の範囲
-
[解決済み] テンプレートでマップを繰り返し処理する
-
[解決済み] bytes.Buffer does not implement io.Writer" というエラーメッセージが表示される。
-
[解決済み] Go で / に異なるメソッドの http リクエストを処理するにはどうすればよいですか?
-
[解決済み] Goによる2変数のForループ
-
[解決済み] 終了コードを取得する - Go
-
GOPATH に関係するファイルを開くにはどうしたらいいですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン