Live data from Hacker News

Inside Rust's Async Transform

blag.nemo157.com

41–50 of 84 posts

Re: Inside Rust's Async Transform

#41

Async/await pattern always confuses me, someone please let me know if I get this right: First, async/await does NOT mean "threading" or "multiprocessing" or "concurrency". It simply means "using a state machine to alternate between tasks, which may or may not be concurrent." Right? Further, in Javascript, futures and async are utilized heavily because we so frequently need to wait for IO events (i.e.: network events)…

Incremental computation can be useful for better responsiveness even if you only have one thread. A simple example in JavaScript would be a Mandelbrot viewer, where you don't want to lock up the UI doing a heavy computation. So, you could have something that looks like an async call that really does the heavy computation in small chunks using idle callbacks, and the future completes when it'd done. (Using a backgroun…

The correct way to deal with that problem is to decouple the UI from the computation, once process for each would be the ideal, anything less is going to messy and require all kinds of hacks to give the same outward appearance. Better still: one supervisor process and one for UI and computation each.

Re: Inside Rust's Async Transform

#42

Async/await pattern always confuses me, someone please let me know if I get this right: First, async/await does NOT mean "threading" or "multiprocessing" or "concurrency". It simply means "using a state machine to alternate between tasks, which may or may not be concurrent." Right? Further, in Javascript, futures and async are utilized heavily because we so frequently need to wait for IO events (i.e.: network events)…

Incremental computation can be useful for better responsiveness even if you only have one thread. A simple example in JavaScript would be a Mandelbrot viewer, where you don't want to lock up the UI doing a heavy computation. So, you could have something that looks like an async call that really does the heavy computation in small chunks using idle callbacks, and the future completes when it'd done. (Using a backgroun…

That's called cooperative multitasking, and it was roughly how things worked in the Windows 3.1 era. Nowadays it's much better to use real threads, as they much better protect against latency (responsiveness) issues.

Re: Inside Rust's Async Transform

#43
post #40
post #15

Earlier quoted context omitted.

Yes, Babel's transform of `async` to ES5 is similar. It turns has to turn a function into a state machine. Rust goes a step further and turns the entire chain of futures into one large combined state machine. But the rest of the event-loop machinery is quite different. JS's async is still fundamentally callback-based. Rust's futures are polled. In JS there's a single global event loop and promises run automagically.…

Thank you for the detailed explanation! Would you mind elaborating on the polled aspect of rust futures, or link me to some documation? Do you mean that there is a loop polling the result of a future? How does that work with things like select?

Futures do nothing until the poll method is called. That method returns an enum, saying if it’s ready, pending, etc. the event loop calls poll repeatedly.

We have some really in depth docs in the works here but it’s not quite ready yet.

Re: Inside Rust's Async Transform

#44
post #40
post #15

Earlier quoted context omitted.

Yes, Babel's transform of `async` to ES5 is similar. It turns has to turn a function into a state machine. Rust goes a step further and turns the entire chain of futures into one large combined state machine. But the rest of the event-loop machinery is quite different. JS's async is still fundamentally callback-based. Rust's futures are polled. In JS there's a single global event loop and promises run automagically.…

Thank you for the detailed explanation! Would you mind elaborating on the polled aspect of rust futures, or link me to some documation? Do you mean that there is a loop polling the result of a future? How does that work with things like select?

Yes, the executor is that loop. Here is an older blog about Rust futures that is still relevant: http://aturon.github.io/2016/09/07/futures-design/

Re: Inside Rust's Async Transform

#46
post #15

Earlier quoted context omitted.

Yes, Babel's transform of `async` to ES5 is similar. It turns has to turn a function into a state machine. Rust goes a step further and turns the entire chain of futures into one large combined state machine. But the rest of the event-loop machinery is quite different. JS's async is still fundamentally callback-based. Rust's futures are polled. In JS there's a single global event loop and promises run automagically.…

Could generating a single combined state machine result in code bloat? (Similar to inlining.)

The state machine here is a struct given to `poll()` methods that advance the state. It's similar to iterator structs that have `next()` calls.

It could cause code bloat, but in practice these are small functions that get inlined and optimized out to almost nothing (sometimes even the whole struct disappears).

Re: Inside Rust's Async Transform

#47

Earlier quoted context omitted.

Incremental computation can be useful for better responsiveness even if you only have one thread. A simple example in JavaScript would be a Mandelbrot viewer, where you don't want to lock up the UI doing a heavy computation. So, you could have something that looks like an async call that really does the heavy computation in small chunks using idle callbacks, and the future completes when it'd done. (Using a backgroun…

The correct way to deal with that problem is to decouple the UI from the computation, once process for each would be the ideal, anything less is going to messy and require all kinds of hacks to give the same outward appearance. Better still: one supervisor process and one for UI and computation each.

Well, in a web app you don't get to make those choices, but you could use a web worker.

Re: Inside Rust's Async Transform

#48
I'll take fibers that yield automatically on blocking operations over async/await most days for most tasks. It's slightly less flexible, since you can only wait for one async action at a time per fiber; but a pleasure to use in comparison. But for that you need fibers built in.

Go sort of does the same thing, but insists on running fibers in separate threads at its convenience; which means giving up the lovely simplicity of cooperative multitasking for the same old multi-threaded circus.

I'm unfortunately not aware of any languages more recent than Smalltalk that get this right. My own baby, Snigl [0], is just getting to the point where it's doable.

[0] https://gitlab.com/sifoo/snigl

Re: Inside Rust's Async Transform

#49

Async/await pattern always confuses me, someone please let me know if I get this right: First, async/await does NOT mean "threading" or "multiprocessing" or "concurrency". It simply means "using a state machine to alternate between tasks, which may or may not be concurrent." Right? Further, in Javascript, futures and async are utilized heavily because we so frequently need to wait for IO events (i.e.: network events)…

Look into continuation-passing style. Semantically, async/await is much like syntactic sugar for CPS (or rather futures, but at the most basic level they can be thought of as single-shot continuations).

But ultimately, to make use of async, you need async primitives - something that lets you say "do this in the background somehow, and let me know once you're done". Any async/await call should ultimately end at one of those primitives, and it's at that point that another call might get interleaved. If you don't actually do I/O or anything else that can do a non-blocking wait, you're not getting anything useful from async.

Re: Inside Rust's Async Transform

#50

I'll take fibers that yield automatically on blocking operations over async/await most days for most tasks. It's slightly less flexible, since you can only wait for one async action at a time per fiber; but a pleasure to use in comparison. But for that you need fibers built in. Go sort of does the same thing, but insists on running fibers in separate threads at its convenience; which means giving up the lovely simpli…

The problem with fibers is interop. The moment you need to do some FFI, especially FFI that involves callbacks, things get a lot more complicated, since code you're calling into/through doesn't have any of that fiber magic (and, depending on how you implemented yours, it might actually break it).
Post reply on HN