I have no intention to make sync channels worse. I've only said that
this redesign does not have a goal of making sync channels faster.
Because I don't know how to do it. When we figure out how to speedup
wait queues, we can do it and it will equally benefit both sync, async
and semaphore channels. And I believe that the proposed select design
won't be road blocker. I mean that we can add further improvements on
top of the proposed design (and not redesign the whole thing from
scratch again).
Regarding particular degradations on sync channels.
You can see that they are quite moderate. Both ChanSync and
ChanProdCons0 are not very interesting, because goroutines are not
doing any useful work, they are just hammering a single channel.
BenchmarkChanSync 127 127 +0.00%
BenchmarkChanSync-2 395 393 -0.51%
BenchmarkChanSync-4 358 340 -5.03%
BenchmarkChanSync-8 293 312 +6.48%
BenchmarkChanSync-16 353 361 +2.27%
BenchmarkChanSync-32 216 220 +1.85%
BenchmarkChanProdCons0 134 140 +4.48%
BenchmarkChanProdCons0-2 407 573 +40.79%
BenchmarkChanProdCons0-4 667 745 +11.69%
BenchmarkChanProdCons0-8 934 883 -5.46%
BenchmarkChanProdCons0-16 760 762 +0.26%
BenchmarkChanProdCons0-32 700 759 +8.43%
BenchmarkChanProdConsWork0 730 691 -5.34%
BenchmarkChanProdConsWork0-2 427 487 +14.05%
BenchmarkChanProdConsWork0-4 767 855 +11.47%
BenchmarkChanProdConsWork0-8 1096 1062 -3.10%
BenchmarkChanProdConsWork0-16 906 965 +6.51%
BenchmarkChanProdConsWork0-32 858 916 +6.76%
The degradations are solely due to added fast path for non-blocking
cases, the overall implementation of sync channels is not changed.
That's the same fast paths that give you:
BenchmarkChanNonblocking 24 8 -66.53%
BenchmarkChanNonblocking-2 92 4 -95.57%
BenchmarkChanNonblocking-4 104 2 -97.95%
BenchmarkChanNonblocking-8 114 1 -99.02%
BenchmarkChanNonblocking-16 92 0 -99.37%
BenchmarkChanNonblocking-32 82 0 -99.46%
BenchmarkSelectNonblock 104 34 -66.92%
BenchmarkSelectNonblock-2 51 17 -66.60%
BenchmarkSelectNonblock-4 25 8 -64.56%
BenchmarkSelectNonblock-8 12 4 -63.44%
BenchmarkSelectNonblock-16 6 2 -63.22%
BenchmarkSelectNonblock-32 5 2 -56.15%
BenchmarkSelectProdCons 1180 1031 -12.63%
BenchmarkSelectProdCons-2 880 683 -22.39%
BenchmarkSelectProdCons-4 1213 433 -64.30%
BenchmarkSelectProdCons-8 1613 578 -64.17%
BenchmarkSelectProdCons-16 1298 805 -37.98%
BenchmarkSelectProdCons-32 1289 773 -40.03%
---
I am not sure whether non-blocking send/recv on sync channels is
particularly important:
select {
case sync_chan <- v:
default:
}
The only reasonable use case I see is polling of stop channel
(essentially using chan as atomic flag):
loop: for {
select {
case <-sync_chan_stop:
break loop
default:
}
// do something useful
}
But the fast paths are definitely important for selects:
select {
case r := <-reqc:
handle r
case <-closec:
...
case <-someOtherUsuallyNonReadyChan:
...
}
I could remove the fast paths from send/recv, and leave them only in
selects. But unfortunately with the current C compiler it's impossible
to do w/o either significant code duplication or additional overheads
for function calls...