1

Under what cases would reflect.Select be needed?

I have found examples, but the use of Select seems contrived.

Any example where reflect.Select is necessary over normal Select?

Godfather
  • 179
  • 2
  • 11

2 Answers2

2

There was a write-up recently from the guys at MongoDB. Apparently this code is in production use in their mongodump utility.

The specific code that uses reflect.Select looks like this (from the article):

// Run multiplexer until it receives an EOF on the control channel.
func (mux *Multiplexer) Run() {
    for {
        index, value, recv := reflect.Select(mux.selectCases)
        EOF := !recv
        // note that the control channel is always at index 0
        if index == 0 {
            if EOF {
                return
            }
            muxInput, _ := value.Interface().(*muxInputSource)
            mux.selectCases = append(mux.selectCases, reflect.SelectCase{
                Dir:  reflect.SelectRecv,
                Chan: reflect.ValueOf(muxInput.collection),
                Send: reflect.Value{},
            })
        } else {
            if EOF {
                mux.writeEOF()
                mux.selectCases = append(mux.selectCases[:index], mux.selectCases[index+1:]...)
            } else {
                document, _ := value.Interface().([]byte)
                mux.writeDocument(document)[]
            }
        }
    }
}

The reasons I can think that they use reflect.Select instead of a straight select:

  • The number of goroutines (and therefore the number of channels) is determined at runtime (using the -j flag). In fact, it seems to change dynamically with append. (credit to @cnicutar's comment)
  • The type of the channel is determined at runtime. This allows their muxInput.collection type to be anything it wants. (credit to @JimB's comment)
chowey
  • 9,138
  • 6
  • 54
  • 84
0

If your channels are fixed, you can use select to watch them; But if your channels is unfixed and you want to watch them, you can use reflect.Select.

There are some code snippet

var (
      events  []reflect.SelectCase
      err     error
      lenHdr  = 3 // zk conn event chan, shutdown chan, children refresh chan
      lenCW   = len(z.ChildWatches)    // a channel slice:chan ChildWatche
      lenDW   = len(z.DataWatches)     //a channel slice:chan DataWatche
      lenEN   = len(z.EphemeralNodes)  //a channel slice: chan EphemeralNode
  )
  events = make([]reflect.SelectCase, lenHdr+lenCW+lenDW+lenEN)
  events[0] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(FreshChanConEvent())} // kick off the event loop
  events[1] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(z.shutdownChan)}
  events[2] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(z.refreshChildChan)}
  for i, _ := range z.ChildWatches {
      events[lenHdr+i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.Zero(reflect.TypeOf((chan zk.Event)(nil)))}
  }
  for i, _ := range z.DataWatches {
      events[lenHdr+lenCW+i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.Zero(reflect.TypeOf((chan zk.Event)(nil)))}
  }
  for i, info := range z.EphemeralNodes {
    events[lenHdr+lenCW+lenDW+i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(info.Ch)}
  }

  for {
    chosen, value, ok := reflect.Select(events)
    if chosen == xxxxx {...}

This code is watching channels array (z.ChildWatches、z.DataWatches、z.EphemeralNodes)

Miffa Young
  • 107
  • 4