Live data from Hacker News

Local async executors and why they should be the default

maciej.codes

21–30 of 327 posts

Re: Local async executors and why they should be the default

#21

> Yes the RwLock and mpsc comes from Tokio and lets you .await instead of blocking a thread, but these are not async primitives, these are multi-threading synchronization primitives. The only reason all this async stuff even exists is because we want concurrency. We want to say "while this one task waits for I/O, this other task will do stuff". So it's not too surprising to me that an intro to async would include syn…

Multi threading and concurrency are not the same. You can have a very high performance server that handles thousands of requests concurrently on a single thread. That's how node/deno do things.

But the way to do things in async rust is that if you want concurrency you also have to use multithreading. At least that is what you see in all the examples and docs.

As soon as you require your futures to be Send you have to use not just concurrency but full blown multithreading primitives.

So e.g. you have to use Arc> where a Rc> would suffice.

Now, to be fair, both futures and tokio support local futures. There is boxed_local (https://docs.rs/futures/latest/futures/future/trait.FutureEx...) and tokio-util even comes with an optional local task pool (https://docs.rs/tokio-util/latest/tokio_util/task/struct.Loc...).

But these features are hidden and certainly not promoted in examples and documentation.

Re: Local async executors and why they should be the default

#22
For me the biggest issue with Async is the management of multiple dependent async calls. It has some weird thing going on and I am not sure which pattern to use exactly. Some functions expect exactly same async fn signature some not and I am not sure why and which one to use.

Re: Local async executors and why they should be the default

#25
post #15

While the article mostly focuses on the cognitive cost, which I deeply sympathize with, I do wonder about the runtime performance cost. Are there any good benchmarks actually quantifying the impact of all that extra thread-safety and the hoops that it adds? I'm not asking simply due personal interest in seeing the numbers, but also because if we want to steer the community towards this non-threadsafe direction it wou…

Anecdotal evidence, but many large rust async code bases perform significantly better if you are using a single threaded runtime vs. a multithreaded runtime.

Here is an issue for the quinn crate that implements QUIC: https://github.com/quinn-rs/quinn/issues/1433

We have had very similar experiences when developing https://github.com/n0-computer/iroh

And this is with quinn still carrying around the synchronization primitives to make everything Send.

Another piece of anecdotal evidence: the functional collection library https://github.com/bodil/im-rs comes in two flavours: one using Arc and one using Rc. The reason for this is that you get a significant performance increase by using Rc (where manipulating the refcount is just an integer inc/dec) vs Arc where manipulating the refcount needs to be an atomic op.

Last but not least - often making futures Send requires you to box your futures. Send and lifetimes just does not play well together. Do something like this:

  trait Foo {
    type OpFut: Future + 'a;
    fn op(&self) -> Self::OpFut
  }
This is what eventually you would want something like async_trait to desugar to. Use the above in a Send context, and you get a completely undecipherable higher-ranked lifetime error. So you are back to boxing all futures.

Re: Local async executors and why they should be the default

#27
In C# i always wondered why they couldn't hide the async/await logic for most cases. I never need to fire off two IO futures at the same time, so just make the thread do other stuff if i'm waiting for IO feedback, don't make me type out async/await in all impacted functions, let the compiler figure out when it can process other stuff

Re: Local async executors and why they should be the default

#28
post #18

This is bad editorializing. You're putting words in the author's mouth that cannot even be found on that page. Don't do that. Edit: Thanks to the mods or whoever fixed it.

I wonder if HN should have a rule that prohibits editorializing.

Not sure if this is facetious, but HN does have a rule that prohibits editorializing. From the Guidelines: "Otherwise please use the original title, unless it is misleading or linkbait; don't editorialize."

Re: Local async executors and why they should be the default

#29

> Yes the RwLock and mpsc comes from Tokio and lets you .await instead of blocking a thread, but these are not async primitives, these are multi-threading synchronization primitives. The only reason all this async stuff even exists is because we want concurrency. We want to say "while this one task waits for I/O, this other task will do stuff". So it's not too surprising to me that an intro to async would include syn…

[deleted]

Re: Local async executors and why they should be the default

#30
post #18

This is bad editorializing. You're putting words in the author's mouth that cannot even be found on that page. Don't do that. Edit: Thanks to the mods or whoever fixed it.

I wonder if HN should have a rule that prohibits editorializing.

Maybe HN should auto-pull title from URL, and then add the posters title as a form of "subtitle/comment"
Post reply on HN