Live data from Hacker News

How to think about async/await in Rust

cliffle.com

1–10 of 268 posts

Re: How to think about async/await in Rust

#2
Not specific to rust, but I think asynchronous programming in general is a hype.

It didn't start because it is so awesome, it started because JS can't do parallel any other way. That's the long and short of it. People wanted to use JS in the backend for some reason. The backend requires concurrency. JS cannot do concurrency. Enter the event loop. Then enter some syntactic sugar for the event loop. And since JS is popular, async became popular.

Code written using threads is, at least to me, much more readable and easier to reason about. Each section in itself is just synchronous code. The runtime/kernel take care of concurrency. The overhead is negligible in a day when we have greenlet implementations. It works for both i/o bound concurrency and cpu bound parallel computing. It doesn't require entire libraries rewritten to support it. There is no callback hell. It scales both horizontically and vertically. Modern languages support it out of the box (Hello `go` keyword).

I realise that this is going to get a lot of downvotes. I don't really care. To me, async is just "cooperative multitasking" with a quick paintjob. We left behind that paradigm in Operating Systems decades ago, and with good reason.

Re: How to think about async/await in Rust

#3

Not specific to rust, but I think asynchronous programming in general is a hype. It didn't start because it is so awesome, it started because JS can't do parallel any other way. That's the long and short of it. People wanted to use JS in the backend for some reason. The backend requires concurrency. JS cannot do concurrency. Enter the event loop. Then enter some syntactic sugar for the event loop. And since JS is pop…

Your comment seems to be conflating concurrency with parallelism.

JS doesn't have any language-level abstractions for parallelism (async or not) but you do have Web Workers[0] and process forking (depending on runtime) to get actual parallel programming. JS async deals with concurrency, not parallelism.

Threads are the opposite: They are interfaces for parallel programming and their use is orthogonal to how your application handles the resulting concurrency.

You say "the runtime/kernel take care of concurrency" - are you telling me you never write a mutex or implement locking logic? Because that's what "taking care of concurrency" is. I'd choose refactoring callback-/Promise-hell over debugging a complex deadlock any day (unless intra-process parallelism is actually a requirement, which may tip the scale in the other direction).

In the context of doing concurrency and parallelism in Rust, I'd 100% agree that the JS/C#-style async/await approach isn't necessarily always the best approach and it's good to consider alternative idioms if your requirements call for it. For anyone writing "apps" or glue-libraries, though, I'm thankful that they stay away from spawning threads all over my system by default and that they need more tools than "learn Rust async in 15 minutes" gives them to become dangerous.

Messing up your single-threaded event-loop concurrency can hog roughly a single CPU core and cause OoM. Messing up thread-based concurrency can have larger implications on the hosting system.

[0]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers...

Re: How to think about async/await in Rust

#4
The article shows a great example of how to implement a state machine with internal delays (do something, wait for a defined time, do something else), which is very useful in a driver or embedded context where you often just have to wait for an external device to be ready.

However, it doesn't really address how you'd construct a state machine with an external tick. It's pretty common to have a state machine called at a fixed frequency. I guess to implement that (using the pending!() Macro between state actions) you'd need to implement a custom executor?

Re: How to think about async/await in Rust

#5

Not specific to rust, but I think asynchronous programming in general is a hype. It didn't start because it is so awesome, it started because JS can't do parallel any other way. That's the long and short of it. People wanted to use JS in the backend for some reason. The backend requires concurrency. JS cannot do concurrency. Enter the event loop. Then enter some syntactic sugar for the event loop. And since JS is pop…

> it started because JS can't do parallel any other way

I remember doing async in C++ with CORBA and ACE's Reactor pattern about 25 years ago, it was not beautiful nor easy.

But if memory serves, most interpreted server side languages used for web programming in the late 2000's didn't have mature multithreading or async capabilities and most of the deployments consisted on exec/forked full application servers. I would also bet that this is exactly what made Node.js popular.

To each its own, async is just another tool in the proverbial belt.

Re: How to think about async/await in Rust

#6

Not specific to rust, but I think asynchronous programming in general is a hype. It didn't start because it is so awesome, it started because JS can't do parallel any other way. That's the long and short of it. People wanted to use JS in the backend for some reason. The backend requires concurrency. JS cannot do concurrency. Enter the event loop. Then enter some syntactic sugar for the event loop. And since JS is pop…

There's a role for async, and it's when you're very I/O bound, you have one thread, and async means you don't need locking. This is simple to think about. That's the classic JavaScript model.

If you have compute-bound components, things get more complicated. If you have threads, locks, and async, all in one program, things get much more complicated. I'm not sure that's a win. At some point, it's easier to use something like Go's green-thread "goroutines", which try not to block, but can block if they have to.

Re: How to think about async/await in Rust

#7

Not specific to rust, but I think asynchronous programming in general is a hype. It didn't start because it is so awesome, it started because JS can't do parallel any other way. That's the long and short of it. People wanted to use JS in the backend for some reason. The backend requires concurrency. JS cannot do concurrency. Enter the event loop. Then enter some syntactic sugar for the event loop. And since JS is pop…

Stackless coroutines are pretty useful to model state machines. I particularly like generators (yield) to model lazy evaluation and iterators.

I do agree however that async as a concurrency approach sucks.

Re: How to think about async/await in Rust

#8

Not specific to rust, but I think asynchronous programming in general is a hype. It didn't start because it is so awesome, it started because JS can't do parallel any other way. That's the long and short of it. People wanted to use JS in the backend for some reason. The backend requires concurrency. JS cannot do concurrency. Enter the event loop. Then enter some syntactic sugar for the event loop. And since JS is pop…

Rust does not have a runtime and making the kernel take care of it is not remotely as efficient.

Re: How to think about async/await in Rust

#9
Thanks for this article.

I feel the goal of a tool should be to make common patterns easy to represent: so "sprinkling async everywhere" only doesn't work because of some common desirable pattern not being easily representable in modern languages and gotchas of the languages.

I have a lightweight thread scheduler written in C and I communicate between threads with a lockless ringbuffer. IO threads do IO. I like the idea of event loops and libuv but I want parallelism.

I wanted to understand how to compile async/await so I wrote a multithreaded unrolled state machine in Java. Each async keyword sends to another thread. I haven't got it to send to a different thread each time to load balance, I need to spend more time on it.

  task1:
    handle1 = async task2();
    handle2 = async task3();
    handle3 = async task4();
    // at this point, I want task2, task3, task4 to be going on in parallel ON DIFFERENT threads
    await handle1;
    await handle2;
    await handle3;
I am designing a notation for concurrency and asynchronocity that is a directly a state machine. I need to write a specification and I'm working on a Java runtime. It looks like this. It's inspired by BNF and Prolog facts.

  thread(s) = state1(yes) | send(message) | receive(message2);
  thread(r) = state1(yes) | receive(message) | send(message2);
I am inspired by Pony lang, Go and Erlang but I think there's still lots of potential innovation in this space that could be had.

Re: How to think about async/await in Rust

#10

Not specific to rust, but I think asynchronous programming in general is a hype. It didn't start because it is so awesome, it started because JS can't do parallel any other way. That's the long and short of it. People wanted to use JS in the backend for some reason. The backend requires concurrency. JS cannot do concurrency. Enter the event loop. Then enter some syntactic sugar for the event loop. And since JS is pop…

Threads are way slower than event loop. Having 2-3 threads with their event loops is massively faster than having every task running on their own thread.
Post reply on HN