5 ms·
Personally I feel like this post misses the forest for the trees. The debate isn't about thread-per-core work stealing executors, it's whether async/await is a
by duped 3y ago
Personally I feel like this post misses the forest for the trees.
The debate isn't about thread-per-core work stealing executors, it's whether async/await is a good abstraction for it in Rust. And the more async code I write the more I feel that it's leaky and hard to program against.
The alternative concurrency model people want is structured concurrency via stackful coroutines and channels on top of a work stealing executor.
Until someone does the work to demo that and compare it to async/await with futures I don't think there's any productive discussion to be had. People who don't like async are going to avoid it and people who don't care about making sure everything and its mother is Send + Sync + 'static are going to keep on doing it.
- withoutboats3 3y agoIn fact there are multiple things in the world that people disagree about. This post addresses a different debate than the one you wanted me to write about, that's all.
- duped 3y agoThe post you quoted and whose author you insulted at the end was talking about this issue.
- withoutboats3 3y agoNo it wasn't. Anyone can follow the link and see that it was about preferring non-work-stealing executors, none of the things you complained about.
- zozbot234 3y agoAIUI, nothing's stopping you from using channels over Rust's existing async support. Stackful coroutines are kinda pointless, since at that point you might as well be using separate threads.
- packetlost 3y agoGreenthreads have their benefits though, especially for massive concurrency.
- littlestymaar 3y agoStackless coroutines are a flavor of green threads though. And without a GC, your stackful coroutines would be using segmented stacks, which is almost indistinguishable to stackless coroutines anyway.
- vacuity 3y agoThe important distinction of stackless coroutines-as-async vs. green threads-as-async is the function coloring problem. I think stackful coroutines are largely obviated given more manageable function coloring, structured concurrency, and whatnot that Rust is currently exploring and working on. Actual OS thread-like preemption probably requires a heavy runtime (I imagine Java can do this for their virtual threads?) or OS support, though. (See scheduler activations for the latter. They might actually catch on this time, who knows?)
- littlestymaar 3y agoI don't think “function coloring” (which is a concept that I find overhyped and uninformative anyway, especially when talking about Rust[1]) has anything to do with the difference between stackful and stackless coroutines: it's about whether you let the language insert yield points automatically or force the programmer to spell them out explicitly. We could make the exact same thing for blocking code by the way: just create two keywords `blocking`/`block` and mark all stdlib function that do trigger a blocking syscall as `blocking` and force the programmer to use the `block` keyword and transitively annotate the calling function as `blocking` and tada! You have static enforcement of blocking code (aka function coloring) in your language without even having any kind of coroutines. It also doesn't have much to do with structured concurrency either, and we could have gotten structured concurrency for free in Rust had tokio decided to cancel tasks handles on drop like futures are. And they even weren't that far of doing so[2] [1]: https://news.ycombinator.com/item?id=36497399 https://news.ycombinator.com/item?id=36497399 [2]: https://github.com/tokio-rs/tokio/issues/1830 https://github.com/tokio-rs/tokio/issues/1830
- kllrnohj 3y ago> The alternative concurrency model people want is structured concurrency via stackful coroutines and channels on top of a work stealing executor. I mean why not just use a thread per connection and not bother with anything fancier at all unless you really truly need to hit those C10M scales? Which I suspect is a very rare need for most things? So many of these articles just go "kernel threads are expensive" and blow on past it as if that's just inherently true & nothing else needs to be said on it. But they really aren't, and unless your work is doing nothing but spawning no-op tasks then the overhead of a "real thread" is likely minimal and in exchange the simplicity you get is tremendous.
- VirusNewbie 3y ago>I mean why not just use a thread per connection and not bother with anything fancier at all unless you really truly need to hit those C10M scales? Which I suspect is a very rare need for most things? At every larger company I've worked for, that breaks down right away. It's really not hard to see how processing some larger proto/json/soap/xml msg can slow the entire system down.
- fulafel 3y agoCan you spell out how processing a large message would result in a bigger system slowdown with thread-per-connection than with async?
- deleted 3y ago[deleted]
- mcguire 3y agoHave a number of threads greater than the number of cores results in either synchronization costs or longer latency.
- IshKebab 3y agoNo it doesn't. It results in more context switching costs maybe, but I seriously doubt that would make a difference in all but the most extreme cases.
- scottlamb 3y ago> The debate isn't about thread-per-core work stealing executors, it's whether async/await is a good abstraction for it in Rust. I think async/await vs stackful coroutines is a more interesting debate [1], but it's definitely not the debate. The quote withoutboats discussed is from a linked article complaining specifically about multi-threaded by default and work-stealing. [1] https://www.reddit.com/r/rust/comments/16p47f1/the_state_of_async_rust_runtimes/k1s1703/ https://www.reddit.com/r/rust/comments/16p47f1/the_state_of_...
- efficax 3y agoYou can use async/await with channels and restrict yourself to only passing immutable references or copy types through arguments to async functions, communicating w/ channels for mutable shared types. Like you could build Erlang style "servers" that own your mutable types and communicate with them over channels. Or you can Arc<Mutex<T>> your way through things. Rust gives you the power to do both.
- zackees 3y ago[dead]