如何在Go中的动态通道列表中选择输入?

poo*_*lie 8 channel go

Go有一种机制可以从几个通道之一select语句中执行阻塞读取.所以你可以说

select {
    case <- c1:
    case <- c2:
}
Run Code Online (Sandbox Code Playgroud)

将阻止,直到我们从这两个通道中的任何一个获得输入.非常好.

但是这需要我在源代码中指定我想要轮询多少个通道.如果我有一个切片或一组通道并且我想阻止直到我得到任何一个输入怎么办?

Dus*_*tin 6

从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)
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以在操场交互方式玩耍


Lil*_*ard 5

只是一个想法,但您可以使用多路复用模式,您可以在其中生成一个带有 2 个通道的 goroutine,该 goroutine 阻塞两个通道并将输出发送到一个新通道。然后,您可以从列表中动态地构建这些树,将所有内容汇集到一个频道中,然后您可以继续阅读。