Comment by the_mitsuhiko
1 year ago
I think the better way to think about async Rust is to use it when it's beneficial to developer productivity and to avoid it when not. There are quite a few situations where it makes the code easier compared to alternatives you could come up with.
I don't think for a second that async Rust should be picked for performance reasons.
You get a feeling for what is a good use of async and bad use of async relatively easily these days as the ecosystem is maturing.
It is increasingly harder to avoid async Rust if you do any form of IO. Most of the useful io based crates assume you are doing async with a very minor amount of them giving you a non async api. Out of the ones that do they are bundling an executor to power that api because they don't want to implement it twice.
I think part of what is feeding this sort of backlash against it is the way that it creates two different rust ecosystems. One of them, the non async version, being decidedly a second class citizen.
It looks like there's good movement on the proposal to bring pollster[1] or similar into the Rust standard library.
I think that's awesome. They've been afraid to "bless" an executor for good reasons, but pollster has 0 chance of "winning" even if blessed since it lacks so many features. However it's a solution to the problem you expressed: I/O crates can be async and used with pollster in sync contexts.
1: https://docs.rs/pollster/latest/pollster/
I haven't been following, would you have a link to this proposal ? A quick search of pollster in rust-lang/rust and rust-lang/rfcs does not bring any interesting result.
1 reply →
What arguments are there for async if not performance? Threads/fibers/gofuncs/actors/... are easier to reason about. Async is super helpful to avoid overhead of thousands of threads, but makes just about everything else harder.
I disagree. I've got several programs with a async select based main loop and others with threads, and the former are easier to reason about in my opinion. Threads hide effects.
However, Tokio tries to be the best of both threads and async and sometimes ends up being the worst of both when Sync/Send/etc creep into function signatures.
Async makes awaiting things much easier than other primitives in the language. So for instance if you both need to wait for stuff to happen on a socket or some event happening, async select makes that super easy.
You can also keep async relatively local to a function that does these things and is itself blocking otherwise.
Yes, async is easier, but granularity of performance is a real downside. The CPU is a resource too, and needs to be managed more carefully than async can do. There's a reason why people stopped using cooperative multitasking like in Windows 3.1 ...
3 replies →
I use (custom-made) actors and (Tokio) channels a lot, and I build them with async.
I do make separate threads when necessary (e.g. to encapsulate blocking I/O).
It can approximate an Erlang experience.
But with a lot more boilerplate and lack of good actor library patterns.
> I think the better way to think about async Rust is to use it when it's beneficial to developer productivity and to avoid it when not.
How do you know if what is best doesn't change as the project you're working on progresses and your manager tosses in new requirements?
I'd say better pick a technique (or even language) that works all the time.
There isn’t one technique that works all the time. Life is unfortunately about tradeoffs whenever you do something complex.
So choose a technique and language that least limits your design freedom.
Choosing performance as your #1 priority is often a bad idea as it gets you into a straight-jacket from the start, making everything else much more difficult and slows down development to a crawl. Unless you're developing an OS kernel perhaps. Computers are fast enough these days, let them do part of the work for you! And you can always write a faster version of your software when there is a demand for it.
2 replies →