6 ms·
Yes, async is effectively a much harder version of Rust, and it's regrettable how it's been shoved down the throats of everyone, while only 1% of projects using
by grug_htmx_dev 3y ago
Yes, async is effectively a much harder version of Rust, and it's regrettable how it's been shoved down the throats of everyone, while only 1% of projects using it really need it. Hover, async is also amazing in these 1% of cases when it's useful.
If you have a service that handles massive amounts of network calls at the core (think linkerd, nginx, etc.), or you want to have a massive amount of lightweight tasks in your game, or working on an embedded software where you want cooperative concurrency, async Rust is an amazing super-power.
Most system/application level things is not going to need async IO. Your REST app is going to be perfectly fine with a threadpool. Even when you do need async, you probably want to use it in a relatively small part of your software (network), while doing most of the things in threads, using channels to pass work around between async/blocking IO parts (aka hybrid model).
Rust community just mindlessly over-did using async literally everywhere, to the point where the blocking IO Rust (the actually better UX one) became a second class citizen in the ecosystem.
Especially visible with web frameworks where there is N well designed async web frameworks (Axum, Wrap, etc.) and if you want a blocking one you get:
tiny_http, absolute bare bones but very well done
rouille - more wholesome, on top of tiny_http, but APIs feel very meh comparing to e.g. Axum
astra - very interesting but immature, and rather barebones
- HippoBaro 3y agoThe argument here is that Rust chose to implement coroutines the wrong way. It went the route of stackless coroutines that need async/await and colored functions. This creates all the friction the article laments over. But it also praises Go for its implementation, which is also based on a coroutine of a different kind. Stackful coroutines, which do not have any of these problems. Rust considered using those (and, at first, that was the project's direction). Ultimately, they went to the stackless operation model because stackfull coroutine requires a runtime that preempts coroutines (to do essentially what the kernel does with threads). This was deemed too expensive. Most people forget, however, that almost no one is using runtime-free async Rust. Most people use Tokio, which is a runtime that does essentially everything the runtime they were trying to avoid building would have done. So we are left in a situation where most people using async Rust have the worst of both worlds. That being said, you can use async Rust without an async runtime (or rather, an extremely rudimentary one with extremely low overhead). People in the embedded world do. But they are few, and even they often are unconvinced by async Rust for their own reasons.
- grug_htmx_dev 3y agoThreads are driven by the OS. Something needs to drive couritines, so there's no way around needing some (even rudimentary, like in embedded) executor. But to be a versatile and universal systems language, Rust can't just build-in executor into a language. I think that stackless coroutines are better than stackfull, in particular for Rust. Everything was done correctly by the Rust team. Again, this is all fair and good, as long as people understand the tradeoff and make good technical decisions around. If they all jump on async bandwagon blind o the obvious limitations, we get where Rust ecosystem is now.
- geodel 3y agoWell people who jumped on async bandwagon are deeply involved in Rust community. So if they do something, others have to assume they are doing it right.
- anonymoushn 3y ago> Rust considered using those (and, at first, that was the project's direction). Ultimately, they went to the stackless operation model because stackfull coroutine requires a runtime that preempts coroutines (to do essentially what the kernel does with threads). This was deemed too expensive. Stackful coroutines don't require a preemptive runtime. I certainly hope that we didn't end up with colored functions in Rust because of such a misconception.
- HippoBaro 3y agoThey often implement soft preemption. Tokio and others like Glommio do. Usually, it's based on interrupts. The runtime schedules a timer to fire an interrupt, and some code is injected into the interrupt handler. This is used to keep track of task runtime quotas so they can yield as soon as possible afterward. This is the same technique used in Go and many others for preemption. If you don't add this, futures that don't yield can run forever, stalling the system. You are right that it is not strictly necessary, but in practice, it is so helpful as a guard against the yielding problem that it's ubiquitous. > I certainly hope that we didn't end up with colored functions in Rust because of such a misconception. Misconceptions are everywhere unfortunately!
- atomicnumber3 3y agoIs there any reason to use async when your platform supports virtual threads? I ask as someone who uses java and is about to rewrite a bunch of code to be able to chuck the entire async paradigm into the trash can and use a blocking model but on virtual threads where blocking is ok.
- HippoBaro 3y agoVirtual threads or green threads, etc., are all names for the same thing: stackful coroutines. I would say yes! If your language/platform/runtime supports them, that should definitely be your starting point.
- nomel 3y ago> that should definitely be your starting point. Could you expand a bit? Why?
- brabel 3y agoNot OP, but synchronous code is much, much easier to understand and write than asynchronous code. What Java is doing is making synchronous code have all the advantages of asynchronous code by making blocking a Thread become a cheap operation (instead of blocking a real OS Thread), making the whole benfit of async code go away while getting rid of async's difficulties, specially in a language that doesn't have async/await (which makes async code "look" synchronous - but in Rust, as this blog post shows, that is not really the case).
- carimura 3y agoHot off the presses from the JVM Language Summit a few weeks ago; The Challenges of Introducing Virtual Threads to the Java Platform [1] [1] https://www.youtube.com/watch?v=WsCJYQDPrrE https://www.youtube.com/watch?v=WsCJYQDPrrE
- Animats 3y ago> Yes, async is effectively a much harder version of Rust, and it's regrettable how it's been shoved down the throats of everyone, while only 1% of projects using it really need it. Yes. I just noticed that Tokio was pulled into my program as a dependency. Again. It's not being used, but I'm using a crate which has a function I'm not using which imports reqwest, which imports h2, which imports tokio.
- grug_htmx_dev 3y agoExactly, because something somewhere needs to make one http call, and it's would be impossible if it wasn't done with scalable async executor. /i
- Klonoar 3y agoPR them to use ureq. ;)
- wrapperup 3y agoI recently did this in a relatively small crate, and it halved the dependencies. Highly recommended if you don't need async.