編集:ペアワイズ還元サンプルコードと回答の並べ替え部を添加します。
「解決策の1つではなく、チャンネルのスライスを持たないようにする」の答えが好ましいです。再構成では、複数のゴルーチンが1つのチャネルに送信できる機能を利用することがよくあります。だから、あなたのソースのそれぞれを別々のチャンネルで送信してから、たくさんのチャンネルから受信することに対処する代わりに、ただ1つのチャンネルを作成し、すべてのソースがそのチャンネルを送信するようにしてください。
Goには、チャンネルの一部から受信する機能はありません。それは頻繁に質問され、ちょうど与えられた解決が好まれる間、それをプログラムする方法があります。あなたが元の質問で "スライスペアを減らす"と言って提案していた解決策は、バイナリの分割と征服の解決策です。 2つのチャンネルを1つに多重化するソリューションがあれば、これはうまくいきます。これのためのあなたのコード例は非常に作業に近いです。
サンプルコードを動作させるためのちょっとした工夫がありません。 nを減らすところで、チャンネル変数をnilに設定する行を追加します。たとえば、コードを読み取った
case v, ok := <-cin1:
if ok {
cout <- v
} else {
n--
cin1 = nil
}
case v, ok := <-cin2:
if ok {
cout <- v
} else {
n--
cin2 = nil
}
}
このソリューションは、あなたが欲しいものと待っていないものを実行します。
それでは、スライスを多重関数にこのソリューションを取り入れた完全な例:私はこのスニペットは、あなたが探しているものと信じてい
package main
import (
"fmt"
"time"
)
func multiplex(cin []chan int, cout chan int) {
var cin0, cin1 chan int
switch len(cin) {
case 2:
cin1 = cin[1]
fallthrough
case 1:
cin0 = cin[0]
case 0:
default:
cin0 = make(chan int)
cin1 = make(chan int)
half := len(cin)/2
go multiplex(cin[:half], cin0)
go multiplex(cin[half:], cin1)
}
for cin0 != nil || cin1 != nil {
select {
case v, ok := <-cin0:
if ok {
cout <- v
} else {
cin0 = nil
}
case v, ok := <-cin1:
if ok {
cout <- v
} else {
cin1 = nil
}
}
}
close(cout)
}
func main() {
cin := []chan int{
make(chan int),
make(chan int),
make(chan int),
}
cout := make(chan int)
for i, c := range cin {
go func(x int, cx chan int) {
for i := 1; i <= 3; i++ {
time.Sleep(100 * time.Millisecond)
cx <- x*10 + i
}
close(cx)
}(i, c)
}
go multiplex(cin, cout)
for {
select {
case v, ok := <-cout:
if ok {
fmt.Println("main gets", v)
} else {
return
}
}
}
}
ああ、非常に良い解決策、明確かつ簡潔です。ありがとうございました! – elpres
複数のゴルーチンの代わりにリフレクションを使用して問題を解決する関数(https://godoc.org/github.com/eapache/channels#Multiplex)を持つパッケージが用意されました。 – Evan