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?
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?
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
:
-j
flag). In fact, it seems to change dynamically with append
. (credit to @cnicutar's comment)muxInput.collection
type to be anything it wants. (credit to @JimB's comment)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)