Как выбрать для ввода в динамический список каналов в Go?
Вопрос
Go есть механизм, чтобы сделать блокировку, чтение от одного из нескольких каналов, Выбрать утверждение. Так что вы можете сказать
select {
case <- c1:
case <- c2:
}
заблокируйте, пока мы не получим ввод из любого из этих двух каналов. Очень хорошо.
Но это требует, чтобы я указываю в исходном коде, сколько каналов я хочу опросить. Что если у меня будет ломтик или массив каналов, и я хочу заблокировать, пока не получишь вклад на любой из них?
Решение
Просто мысль, но вы можете использовать мультиплексирование шаблона, где вы нередитесь от Goroutine с 2 каналами, которые блокируются как на обоих, и отправляют вывод на новый канал. Тогда вы можете просто создать дерево из них динамически из вашего списка, который востребован все на один канал, который вы тогда читаете.
Другие советы
С GO1.1 есть правильный API для динамически выбора наборов.
Вот полный и используемый пример:
package main
import (
"log"
"reflect"
)
func sendToAny(ob int, chs []chan int) int {
set := []reflect.SelectCase{}
for _, ch := range chs {
set = append(set, reflect.SelectCase{
Dir: reflect.SelectSend,
Chan: reflect.ValueOf(ch),
Send: reflect.ValueOf(ob),
})
}
to, _, _ := reflect.Select(set)
return to
}
func recvFromAny(chs []chan int) (val int, from int) {
set := []reflect.SelectCase{}
for _, ch := range chs {
set = append(set, reflect.SelectCase{
Dir: reflect.SelectRecv,
Chan: reflect.ValueOf(ch),
})
}
from, valValue, _ := reflect.Select(set)
val = valValue.Interface().(int)
return
}
func main() {
channels := []chan int{}
for i := 0; i < 5; i++ {
channels = append(channels, make(chan int))
}
go func() {
for i := 0; i < 10; i++ {
x := sendToAny(i, channels)
log.Printf("Sent %v to ch%v", i, x)
}
}()
for i := 0; i < 10; i++ {
v, x := recvFromAny(channels)
log.Printf("Received %v from ch%v", v, x)
}
}
Вы можете играть с этим в интерактивном режиме на игровая площадка
package main
import "fmt"
func main() {
c1 := make(chan int)
c2 := make(chan int)
go func() { c1 <- 1 }()
go func() { c2 <- 2 }()
cs := []chan int{c1, c2}
cm := make(chan [2]int)
for idx, c := range(cs) {
go func(idx int, c chan int) {
cm <- [2]int{idx, <-c}
}(idx, c)
}
fmt.Print(<-cm)
fmt.Print(<-cm)
}
принты [0 1][1 2]
(или, может быть [1 2][0 1]
).
Возможно, что-то вроде этого может подать заявку?
// multiplex takes a slice of chan ints and returns a channel
// that multiplexes between all of them.
func multiplex(chs []<-chan int) <-chan int {
c := make(chan int)
d := make(chan bool)
for _, ch := range chs {
go func(ch <-chan int) {
for r := range ch {
c <- r
}
d <- true
}(ch)
}
go func() {
for i := 0; i < len(chs); i++ {
<-d
}
close(c)
}()
return c
}