Live data from Hacker News

Async-await on stable Rust

blog.rust-lang.org

371–380 of 392 posts

Re: Async-await on stable Rust

#371

Earlier quoted context omitted.

Have you ever heard of Esterel or Céu? They follow the synchronous concurrency paradigm, which apparently has specific trade-offs that give it great advantages on embedded (IIRC the memory overhead per Céu "trail" is much lower than for async threads (in the order of bytes ), fibers or whatnot, but computationally it scales worse with the nr of trails). Céu is the more recent one of the two and is a research language…

I hadn't heard of "synchronous concurrency", but looking at the Céu paper (only briefly so far), I think the model looks very close to how `async`/`await` works in Rust - possibly even isomorphic. This is really exciting, because Rust's model is unique among mainstream languages (it does not use green threads or fibers, and in fact does not require heap allocation), and I wasn't previously aware of any similar models…

That is a correct understanding of how `await` works in Céu. What is important to note however is that all trails must have bounded execution, which means having an `await` statement. One abstraction that Céu uses is the idea that all reactions to external events are "infinitely" fast - that is, all trails have bounded execution, and computation is so much faster than incoming/outgoing events that it can be considered instantaneous. It's a bit like how one way of looking at garbage collected languages is that they model the computer as having infinite memory.

Having said that, the combination of par/or and par/and constructs for parallel trails of execution, and code/await for reactive objects is like nothing I have ever seen in other languages (it's a little bit actor-modelish, but not quite). I haven't looked closely at Rust though.

Céu also claims to have deterministic concurrency. What it means by that is that when multiple trails await the same external event, they are awakened in lexical order. So for a given sequence of external events in a given order, execution behavior should be deterministic. This kind of determinism seems to be true for all synchronous reactive languages[0]. Is the (single-threaded) concurrency model in Rust comparable here?

The thesis is a bit out of date (only slightly though), the manual for v0.30 or the online playground might be a better start[1][2].

[0] which is like... three languages in total, hahaha. I don't even remember the third one beyond Esterel and Céu. The determinism is quite important though, because Esterel was designed with safety-critical systems in mind.

[1] https://ceu-lang.github.io/ceu/out/manual/v0.30/

[2] http://ceu-lang.org/try.php

Re: Async-await on stable Rust

#372
post #359

Earlier quoted context omitted.

> Sure, but that overhead is also not essential, but a feature of Go's particular implementation. The only way to get around the FFI performance problem would be for all fibers to have big stacks. At that point you've thrown away their biggest selling points: high scalability and fast spawning.

> The only way to get around the FFI performance problem would be for all fibers to have big stacks. I don't know all of Rust's specific constraints, but it is not the case in general. There are two levels for FFI support in this context, based on whether you want to allow FFI to block the lightweight thread (perhaps through an upcall), or not. Only if you want to allow that do you need "big stacks", but even then th…

> Depending on your FFI, if you don't allow the FFI code to hold pointers into you language's stack, you're all good.

Rust does this with virtually all FFI.

Re: Async-await on stable Rust

#373

Earlier quoted context omitted.

You can't "avoid state". State is essential to any computation. The only question is, can you express some of the state-relations as serial code? If "relationships became intricate (a computation graph)", chances are, you shouldn't use serial code anymore, because that splits dependencies in a two-class society: those that are expressed using code and those that are expressed using dead data. It is usually preferable…

Haskell avoids state. When I say state I meant "shared state" is the bane of multithreading. Amdahl's law show that if 95% of your code is parallel you limit your speedup to 20x even with thousands of cores, any shared state contribute to those 5%.

> Haskell avoids state.

That's a myth. You need state for computation. It's not a language issue. You need just as much state in Haskell as you need in other languages. In Haskell you just specify each little component as a function which takes as a parameter what is effectively global state.

Which, by the way, is usually a bad idea because it causes so much boilerplate. Plus, it makes it unclear how many instances of a given concept can actually exist in a running program.

Re: Async-await on stable Rust

#374
post #368

Earlier quoted context omitted.

> Can you give one that reaches this goal? First-class continuations. They are an efficient building block for everything from calling asynchronous I/O routines without turning your code into callback spaghetti, to implementing coroutines and green threads. Goroutines are a special and poorly implemented case of continuations. Gambit-C has had preemptive green threads with priorities and mailboxes at less than 1KiB p…

First-class continuations are too unrestricted to match the performance of Rust-style async/await. If you take on a few limitations you can get there, but then those are exactly the things people complain about.

It is worse than that. First-class continuations add a small overhead for stack operations, and they always have more memory overhead than callbacks/async transformation into callbacks. But the comment I was replying was about Go, not Rust. For the small overhead that first-class continuations have, they provide a simple and efficient way to handle coroutines, generators, asynchronous I/O, and green threads.

Re: Async-await on stable Rust

#375

Earlier quoted context omitted.

Those don't actually execute simultaneously in Javascript, though. In Javascript, C# and I suspect Java, each usage of await generates a state machine that can _defer execution_. So while one function is blocked, another can continue to execute. The concept is the same in Rust, except in Rust a nested await does not generate a new state machine. The entire async operation just uses a single state machine. The reason…

Java actually doesn't have async/await as a language level feature. It does have the Future interface, but it's just an interface, and not special in any way.

Got it, thanks for the info!

Re: Async-await on stable Rust

#376
post #306

Earlier quoted context omitted.

Another infrequent toe dipper here - say you need to send some command to a peripheral, wait for the device to acknowledge it, then send more data. The naive implementation would poll for the interrupt or just go to sleep, meaning no other user code can run in that time. A naive async implementation would spread your code all over the place - it wouldn't just be a function call with three statements. There are librar…

>poll for the interrupt Errr, no. You either poll, or set up an interrupt to catch an event. The point of an interrupt is to allow other code to continue to run while waiting for a peripheral.

Sorry, I mean polling for the ready register, not interrupt.

Re: Async-await on stable Rust

#377

Earlier quoted context omitted.

BEAM (Erlang VM) provides pre-emptive scheduling

True for functions written in Erlang/Elixir, but not in NIF functions implemented in C.

Thanks to dirty schedulers that is not a big issue: https://medium.com/@jlouis666/erlang-dirty-scheduler-overhea...

Re: Async-await on stable Rust

#378
post #158
post #88

Earlier quoted context omitted.

related: async/await is also amazingly useful for game development. Stuff like writing an update loop, where `yield` is "wait until next frame to continue". This can let you avoid a lot of the pomp and circumstance of writing state machines by hand.

I played around with exactly that concept during Ludum Dare last month, if you're interested: https://github.com/e2-71828/ld45/blob/master/doc.pdf

I don't know any rust,. but that was a really good read. what is your background, and what materials did you use getting into Rust?

Your explanations were surprisingly simple

Re: Async-await on stable Rust

#379

Earlier quoted context omitted.

True for functions written in Erlang/Elixir, but not in NIF functions implemented in C.

Thanks to dirty schedulers that is not a big issue: https://medium.com/@jlouis666/erlang-dirty-scheduler-overhea...

Thanks for the link. It's a very deep and interesting technical post.

Re: Async-await on stable Rust

#380
post #158

Earlier quoted context omitted.

I played around with exactly that concept during Ludum Dare last month, if you're interested: https://github.com/e2-71828/ld45/blob/master/doc.pdf

I don't know any rust,. but that was a really good read. what is your background, and what materials did you use getting into Rust? Your explanations were surprisingly simple

Thanks. I was a software engineer at several different SF-area companies for about a decade, and then I decided to take some time off from professional programming. I'm now a full-time student in a CS Master's program. As I'll eventually need to produce a thesis, this was partly an exercise to practice my technical writing.

I picked up Rust for my personal projects a couple of years ago, and mostly worked from the official API docs, occasionally turning to blog posts, the Rust book, or the Rustonomicon. Because I didn't have any time pressure, I ignored the entire crate ecosystem and opted to write everything myself instead. This has left some giant gaps in my Rust knowledge, but they're in a different place than is typical.

As far as the explanations go, I realized that good authors don't say important things only once: they repeat everything a few different times in a few different ways. So, I tried to say the exact same things in the prose as in the code listings, and trusted that the fundamental differences between Rust and English would make the two complement each other instead of simply being repetitive.

Post reply on HN