I am experimenting with generalizing the single-channel select optimizations done by the compiler to multiple channels.
A quick
prototype implemented in the runtime looks
promising, but before spending too much time on it (there's one regression that needs work) I wanted to ask for help in understanding if the approach is, in general, ok from the perspective of the language spec.
I tried to
ask on gophers slack, but we could not find a good argument as to why this shouldn't be allowed.
The gist of the idea is to try to avoid locking all channels, if we detect that any of the channels is ready and can proceed.
For this though it requires the following transformations to be allowed by the spec. Anybody knows?
select {
case <-f1():
case <-f2():
default:
// body default
}
transformed into (randbool returns a pseudorandom uniform bool value)
c1, c2 := f1(), f2()
if randbool() {
c1, c2 = c2, c1
}
select {
case <-c1:
default:
select {
case <-c2:
default:
// body default
}
}
blocking case
select {
case <-f1():
case <-f2():
}
transformed into
c1, c2 := f1(), f2()
if randbool() {
c1, c2 = c2, c1
}
select {
case <-c1:
default:
select {
case <-c2:
default:
select {
case <-c1:
case <-c2:
}
}
}
The one I'm least confident about is the non-blocking case, as I'm specifically not sure whether picking the default case in that way is correct. This could possibly be a safer, but slower, approach:
c1, c2 := f1(), f2()
if randbool() {
c1, c2 = c2, c1
}
select {
case <-c1:
default:
select {
case <-c2:
default:
select {
case <-c1:
case <-c2:
default:
// body default
}
}
}
Thoughts?
Carlo Alberto