Live data from Hacker News

How to think about async/await in Rust

cliffle.com

171–180 of 268 posts

Re: How to think about async/await in Rust

#171

Earlier quoted context omitted.

In the broad use case where you have an IO-bound server, how is this solution better than async? It sounds like your non-async solution was to reimplement async, which shows the value of the feature.

I reimplemented async, except that the event loop is only invoked explicitly and under the programmer's control. I know it doesn't sound like a lot, but it is.

Is the idea that you might be fanning out and want to delay starting the event loop? Fanning out in JS looks like:

  const fn = async (arg) => { ... };  // calls some RPC
  const results = await Promise.all(args.map(fn))
which might technically be starting the first func before the second is in the event loop, but I don't see why that matters for what I'm doing.

Re: How to think about async/await in Rust

#172

Earlier quoted context omitted.

In the broad use case where you have an IO-bound server, how is this solution better than async? It sounds like your non-async solution was to reimplement async, which shows the value of the feature.

I reimplemented async, except that the event loop is only invoked explicitly and under the programmer's control. I know it doesn't sound like a lot, but it is.

async event loops in Rust are invoked explicitly by the programmer as well.

Re: How to think about async/await in Rust

#173

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…

The biggest benefit of async/await is imo. in GUI programming where you simply can't have blocking code a lot of the time, and moving everything between the GUI thread and the backend thread can be rather costly and annoying as well as buggy if people are not 100% aware which thread accesses what. I find it rather odd that you say "easier to reason about.". I find it much harder to keep a mental model in my head whic…

> in GUI programming where you simply can't have blocking code a lot of the time,

This can be transparently solved by the GUI library. The main thread does a loop and polls events from a queue. Those events are generated by a gui on another thread. It can be designed so gui itself can be manipulated on the mainpulated on the main thread, and the event handling and rendering is double buffered, or synchronized for you.

> easier to reason about

The style of code OP is describing looks like `if then else`. You can reason about the state of the system using traditional programming logic.

Re: How to think about async/await in Rust

#174

Earlier quoted context omitted.

I reimplemented async, except that the event loop is only invoked explicitly and under the programmer's control. I know it doesn't sound like a lot, but it is.

Is the idea that you might be fanning out and want to delay starting the event loop? Fanning out in JS looks like: const fn = async (arg) => { ... }; // calls some RPC const results = await Promise.all(args.map(fn)) which might technically be starting the first func before the second is in the event loop, but I don't see why that matters for what I'm doing.

It does matter for what I'm doing.

Re: How to think about async/await in Rust

#175
post #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 somethi…

> when you're very I/O bound, you have one thread

Yes, but this is very unusual. In a web server, you have pool of threads that can respond to incoming connections. When one is blocking, another is ready to go. All the transition are handled transparently by the kernel.

Re: How to think about async/await in Rust

#176
post #172

Earlier quoted context omitted.

I reimplemented async, except that the event loop is only invoked explicitly and under the programmer's control. I know it doesn't sound like a lot, but it is.

async event loops in Rust are invoked explicitly by the programmer as well.

Are they always invoked explicitly? Or is it sometimes implicit?

Re: How to think about async/await in Rust

#177

Hiding an asynchronous, co-routine, style program flow behind a syntax which looks like a sequential program flow is IMHO a design mistake I wish Rust had not made. It's partially hiding what's under the surface.It makes programs harder to reason about. And, worst, it "infects" whole programs pushing async further and further up the call-chain, as the "sync to async" boundary is not a good story in Rust. Finally the…

Last time I used Rust was long ago, before it even had async, so idk what the outcome looks like. What kinds of libs depend on async in an infectious way? Cause if they didn't, the only alternatives seem to be spawning threads or asking for a threadpool.

Re: How to think about async/await in Rust

#178

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…

The alternative with threads on an IO-bound server eventually cycles back to async/await but with extra steps. You write synchronous request handlers until you notice IO-waits wasting all your thread time, add more threads to the pool, start hitting overhead from that, then implement greenthreads. NodeJS did it right, and it's hard to call a 14-year-old technology a fad.

> add more threads to the pool, start hitting overhead from that

I would like to know more detail about this claim.

The scenario you are describing is one were 64-128 OS threads are fully blocked waiting for IO. If that's the case, is it likely that you will have additional unused IO resources that could be being utilized?

Also, what overhead do you see as the main limit on spawning a lot of threads? Is that the CPU time of context switching? If so, in this scenario CPU is not the bottleneck, and switching between processes will be nothing, especially with a 32-64 core CPU.

This is a genuine question as I have never worked on an application that got close to maxing out either approach.

Re: How to think about async/await in Rust

#179

Concurrency is like a single cook preparing many different recipes at the same time, and parallelism is multiple cooks in the same kitchen. Single-threaded processes can use async/await to context switch and it feels like parallelism but it's not unless you're executing each task to its own OS thread. ... and that didn't click for me until I understood that concurrency (async/await) and parallelism (multiple OS threa…

Yeah, async is a type of greenthreading.

Re: How to think about async/await in Rust

#180

Hiding an asynchronous, co-routine, style program flow behind a syntax which looks like a sequential program flow is IMHO a design mistake I wish Rust had not made. It's partially hiding what's under the surface.It makes programs harder to reason about. And, worst, it "infects" whole programs pushing async further and further up the call-chain, as the "sync to async" boundary is not a good story in Rust. Finally the…

Last time I used Rust was long ago, before it even had async, so idk what the outcome looks like. What kinds of libs depend on async in an infectious way? Cause if they didn't, the only alternatives seem to be spawning threads or asking for a threadpool.

HTTP client library is the one that got me yesterday. "reqwest" has a blocking mode, but it's less featureful than its async version, and the code I needed to do signing etc was only possible with the async API.

I don't think this is the right way to design libraries; I think the right thing to do is to expose the state machine etc that drives the I/O and then provide async and sync entry points to the same thing. But 'async' keyword makes it too easy to just sprinkle it all the way down, and now you've imposed your lifestyle choices on your user.

Post reply on HN