Как выбрать для ввода в динамический список каналов в Go?

StackOverflow https://stackoverflow.com/questions/4220745

  •  26-09-2019
  •  | 
  •  

Вопрос

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
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top