6 ms·
Furthermore, channels are slow. I only use them when performance doesn't matter, and even then I end up rewriting them into a mutex half of the time and simplif
by eloff 10y ago
Furthermore, channels are slow. I only use them when performance doesn't matter, and even then I end up rewriting them into a mutex half of the time and simplifying the code in the process. It was a nice idea in theory, but the implementation is full of usage pitfalls and performance issues.
I use queues of my own implementation when I really need performance. But then I have lots of experience with that, and I have the implementation of maybe the world's highest throughput SPSC queue, outperforming the Lynx queue that was featured here on HN earlier in the year. I'm still trying to make time to write that up properly as a blog post (I hate writing blog posts.)
- netheril96 10y agoMaybe you should contribute to the go development to improve the performance for everyone.
- kasey_junk 10y agoThere have been many discussions over the years about augmenting channels so that they can be more performant in specific instances like spsc or spmc. The language maintainers have not been very receptive and the broader community has at times been outright hostile.
- eloff 10y agoThey have Dmitry Vyukov, who's better at that kind of thing than me. If they want to fix the problem, they don't need my help. I would rather publish my work, and if they want to adapt it for Go's channels, they can do that with my blessing. To me the tricky part seems to be how they need an implementation good for all cases. Performance engineering is all about tradeoffs. Memory usage, throughput, latency are often competing requirements and you have to choose one. Furthermore, unless they can somehow statically determine how many threads access a channel, they have to use a MPMC queue, which is a performance anti-pattern. I would modify the language (maybe just make() builtin) to allow specifying what type of Channel is needed where, SPSC, MPSC, SPMC, etc. But we all know how that would be received.
- zzzcpan 10y agoIf you control both the compiler and the scheduler these optimizations become somewhat easier and without any syntax changes, no? Like removing naive synchronization on channel operations and having scheduler to deal with them, tracking states, amortizing synchronization, etc.
- eloff 10y agoSome become easier, yes. But I don't think it's that easy to tell how many threads access a channel. We have runtime race-checkers precisely because we don't know how to check that at compile time. Whether the specific case of channels in Go is easier, I don't know. You can in Rust because the language makes you specify which threads owns what and two threads can't own the same thing at the same time (as I understand it anyway.)
- Animats 10y agoI looked at the "select" code in the early days. A "select" with one case is compiled inline and is fast. A select with more than one case calls a very complex library function for N-way selects. In practice, most selects are N=1 or N=2; N>2 is rare. N=2 needs to be handled as a special case, if it hasn't been yet.