HiveBrain v1.2.0
Get Started
← Back to all entries
snippetgoCritical

how to listen to N channels? (dynamic select statement)

Submitted by: @import:stackoverflow-api··
0
Viewed 0 times
howstatementdynamicchannelslistenselect

Problem

to start an endless loop of executing two goroutines, I can use the code below:

after receiving the msg it will start a new goroutine and go on for ever.

c1 := make(chan string)
c2 := make(chan string)

go DoStuff(c1, 5)
go DoStuff(c2, 2)

for ; true;  {
    select {
    case msg1 := <-c1:
        fmt.Println("received ", msg1)
        go DoStuff(c1, 1)
    case msg2 := <-c2:
        fmt.Println("received ", msg2)
        go DoStuff(c2, 9)
    }
}


I would now like to have the same behavior for N goroutines, but how will the select statement look in that case?

This is the code bit I have started with, but I am confused how to code the select statement

numChans := 2

//I keep the channels in this slice, and want to "loop" over them in the select statemnt
var chans = [] chan string{}

for i:=0;i<numChans;i++{
    tmp := make(chan string);
    chans = append(chans, tmp);
    go DoStuff(tmp, i + 1)

//How shall the select statment be coded for this case?  
for ; true;  {
    select {
    case msg1 := <-c1:
        fmt.Println("received ", msg1)
        go DoStuff(c1, 1)
    case msg2 := <-c2:
        fmt.Println("received ", msg2)
        go DoStuff(c2, 9)
    }
}

Solution

You can do this using the Select function from the reflect package:


func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool)


Select executes a select operation described by the list of cases. Like
the Go select statement, it blocks until at least one of the cases can
proceed, makes a uniform pseudo-random choice, and then executes that
case. It returns the index of the chosen case and, if that case was a
receive operation, the value received and a boolean indicating whether
the value corresponds to a send on the channel (as opposed to a zero
value received because the channel is closed).

You pass in an array of SelectCase structs that identify the channel to select on, the direction of the operation, and a value to send in the case of a send operation.

So you could do something like this:

cases := make([]reflect.SelectCase, len(chans))
for i, ch := range chans {
cases[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(ch)}
}
chosen, value, ok := reflect.Select(cases)
// ok will be true if the channel has not been closed.
ch := chans[chosen]
msg := value.String()


You can experiment with a more fleshed out example here: http://play.golang.org/p/8zwvSk4kjx

Context

Stack Overflow Q#19992334, score: 189

Revisions (0)

No revisions yet.