Rust 1.39.0 released
So, what is async await? Async-await is a way to write functions that can 'pause', return control to the runtime, and then pick up from where they left off. Typically those pauses are to wait for I/O, but there can be any number of uses."
Posted Nov 7, 2019 16:08 UTC (Thu)
by ms-tg (subscriber, #89231)
[Link] (3 responses)
Posted Nov 7, 2019 19:21 UTC (Thu)
by rahulsundaram (subscriber, #21946)
[Link] (2 responses)
Posted Nov 8, 2019 1:26 UTC (Fri)
by ms-tg (subscriber, #89231)
[Link] (1 responses)
From the post:
> Seeing code written like this that compiled down to one state machine, with full code and data inlining, and no extra allocations, was captivating. You may as well have dropped out of the sky on a flying motorcycle and told me that magic exists, and I was a wizard.2
Posted Nov 8, 2019 1:36 UTC (Fri)
by ms-tg (subscriber, #89231)
[Link]
> At the time, I’d been writing some asynchronous object-oriented state machines by hand in C++11. This experience had been so difficult and error-prone that once I read Aaron’s post, it was inception: I couldn’t get the idea out of my head, and more than anything, I wanted to start using Rust at my job. Eventually, this led me to make a fateful decision, and find a new job where I could invest more of my time in Rust. But that’s another story for another day.
Posted Nov 7, 2019 20:53 UTC (Thu)
by zorro (subscriber, #45643)
[Link] (23 responses)
To my untrained eye it looks like user mode scheduling, except that the runtime is not sophisticated enough to provide a simple fiber abstraction so instead forces the programmer to pollute their code with async/awaits everywhere.
Posted Nov 7, 2019 21:33 UTC (Thu)
by NAR (subscriber, #1313)
[Link] (1 responses)
Posted Nov 8, 2019 3:24 UTC (Fri)
by mathstuf (subscriber, #69389)
[Link]
I suggest reading the blogs in the last few This Week in Rust summaries. There's lots of good discussion and explanation in them.
Posted Nov 7, 2019 22:28 UTC (Thu)
by pkolloch (subscriber, #21709)
[Link] (8 responses)
Async functions themselves don't execute the bulk of the code when called but return a Future which doesn't do much unless it is passed to an executor. All this ceremony allows IO heavy functions to compile to state machines that don't need heap allocations under the hood.
It is very cool for this use case and its efficiency. Especially, in combination with the extended guarantees of Rust that go beyond memory safety without using garbage collection: no data races.
Posted Nov 7, 2019 22:33 UTC (Thu)
by atai (subscriber, #10977)
[Link] (7 responses)
Posted Nov 7, 2019 22:58 UTC (Thu)
by roc (subscriber, #30627)
[Link] (1 responses)
Posted Nov 7, 2019 22:59 UTC (Thu)
by roc (subscriber, #30627)
[Link]
Posted Nov 7, 2019 23:24 UTC (Thu)
by alsuren (subscriber, #62141)
[Link] (4 responses)
Async functions are super-common in managed languages like C# JS and Python. Rust manages to get similar ergonomics, with an execution model that allows pluggable schedulers and all sorts of interesting performance properties. Naturally everyone is quite excited.
I suspect that you could build something similar on top of stackless coroutines, but writing a multithreaded work-stealing scheduler in C++ doesn't sound fun. There is also a perception that async/await is a pattern that is mostly useful for writing web services, and that C++ is not a language that you want web developers to use. Us web devs write enough security vulnerabilities as it is in memory-managed languages. Can you imagine what would happen if you got a bunch of rushed web devs to write multithreaded C++ and then exposed it to the internet?
Posted Nov 8, 2019 17:04 UTC (Fri)
by kleptog (subscriber, #1183)
[Link] (3 responses)
The real awesomeness is combining this with generators. Now you can easily loop over data structures in memory, but then you can have iterators that iterate over data that has to be retrieved over the network.
But you're right that it's mostly useful for network stuff, since that's the most common thing to wait on. Async I/O for disks just isn't as well supported or useful. And it requires compiler support, because it requires significant transformations of the structure of the code.
Posted Nov 8, 2019 22:23 UTC (Fri)
by joib (subscriber, #8541)
[Link] (2 responses)
Speaking of which, any project wiring up Rust async/await with io_uring?
Posted Nov 9, 2019 4:16 UTC (Sat)
by mathstuf (subscriber, #69389)
[Link] (1 responses)
https://www.reddit.com/r/rust/comments/dtfgsw/iou_rust_bi...
Posted Nov 20, 2019 11:01 UTC (Wed)
by ms-tg (subscriber, #89231)
[Link]
Posted Nov 7, 2019 22:57 UTC (Thu)
by roc (subscriber, #30627)
[Link] (2 responses)
Posted Nov 8, 2019 20:56 UTC (Fri)
by ms-tg (subscriber, #89231)
[Link] (1 responses)
Interesting! The position of this paper is to argue *against* stack-ful coroutines (Fibers), and explicitly *for* stackless coroutines (async/await) as a superior alternative. And therefore, that there are not...
> ...enough motivating reasons for C++ language to adopt and maintain a highly-platform dependent facility
Based on the lack of context in the initial post, I had assumed incorrectly this paper would be arguing against async/await, rather than for it - did you read the paper differently?
Posted Nov 8, 2019 21:37 UTC (Fri)
by roc (subscriber, #30627)
[Link]
Posted Nov 8, 2019 1:12 UTC (Fri)
by flussence (guest, #85566)
[Link] (7 responses)
Posted Nov 8, 2019 7:12 UTC (Fri)
by zorro (subscriber, #45643)
[Link] (6 responses)
Posted Nov 8, 2019 8:08 UTC (Fri)
by Cyberax (✭ supporter ✭, #52523)
[Link]
But async/await can be used for higher-level scheduling, yes.
Posted Nov 8, 2019 13:49 UTC (Fri)
by zwol (guest, #126152)
[Link]
Posted Nov 8, 2019 19:58 UTC (Fri)
by farnz (subscriber, #17727)
[Link]
Because async/await isn't really about task scheduling logic (at least in Rust) - it uses that name because then it's familiar to programmers coming from languages like Python.
Instead, it's syntax sugar for constructing a state machine - you write code as-if you were not writing a state machine, putting in `.await` at points where you want to delay changing state until another state machine has also changed state, and the compiler generates your new state machine for you.
At the very bottom of the stack of state machines you're creating, you usually have small state machines that change state in response to external events - for example, a socket might change state when there is new data to read - and that's how you end up with a top-level state machine that's useful. But it's state machines all the way down, just written nicely.
If you actually want task scheduling, there's thread APIs for that, but the state machine representation tends to perform better on real systems than the tasks representation of a solution, because the size of the state machine's saved state at points where it waits for another state machine to change state tends to be much smaller than the size of a task stack that can be switched out at any time.
Posted Nov 8, 2019 22:48 UTC (Fri)
by roc (subscriber, #30627)
[Link] (1 responses)
If you have a different solution no-one has thought of, please let the world know.
Also, as zwol noted, syntactic separation of async from run-to-completion code also helps reasoning about program behaviour. For languages like Rust where the compiler effectively forces you to prove safety, this means in general the code you are allowed to write in a function is different depending on the await-points it contains. (This is better than in C++, where the code you are allowed to write is the same, but the wrong code will exploitably crash.)
Posted Nov 8, 2019 22:55 UTC (Fri)
by roc (subscriber, #30627)
[Link]
Posted Nov 10, 2019 0:15 UTC (Sun)
by ofranja (guest, #11084)
[Link]
async declarations in Rust are just there to ease declarations and for error message ergonomics, since you could explicitly return a Future type for any async function before this support landed on stable Rust.
Posted Nov 16, 2019 9:00 UTC (Sat)
by iq-0 (subscriber, #36655)
[Link]
Rust already had a whole ecosystem based around futures and combinators for doing async logic. But using it turns out to be quite complex in combination with the ownership and borrowing model of Rust. This leads to a lot of small allocations and unergonomic code.
What `async`/`await` add to this is a way that the compiler can see where the suspension/resumation of logic is and thus can “prove” that the ownership and borrowing rules aren’t being violated.
Thus, apart from bringing the same easy of writing async code like you’d write normal code, you can now write this logic without having to jump through hoops that were needed to satisfy the borrow-checker.
Posted Dec 4, 2019 12:19 UTC (Wed)
by kitanatahu (guest, #44605)
[Link] (1 responses)
From the article on this:
Posted Dec 4, 2019 12:39 UTC (Wed)
by mathstuf (subscriber, #69389)
[Link]
Rust 1.39.0 released
Rust 1.39.0 released
Rust 1.39.0 released
https://tmandry.gitlab.io/blog/posts/optimizing-await-1/
Rust 1.39.0 released
Rust 1.39.0 released
Rust 1.39.0 released
Rust 1.39.0 released
Rust 1.39.0 released
Rust 1.39.0 released
Rust 1.39.0 released
Rust 1.39.0 released
Rust 1.39.0 released
Rust 1.39.0 released
Rust 1.39.0 released
Rust 1.39.0 released
https://github.com/withoutboats/iou
https://docs.rs/iou/0.1.0/iou/
Rust 1.39.0 released
Rust 1.39.0 released
Rust 1.39.0 released
Rust 1.39.0 released
Rust 1.39.0 released
Rust 1.39.0 released
Rust 1.39.0 released
In my personal bitter experience, I don't want the async stuff hidden away under the hood. You know how extremely threaded code is a nightmare to debug because it's so easy to miss a race condition? Making the suspension points explicit in every subroutine is a huge help with that. It cuts the state space of possible execution traces down to something a human can reasonably keep in their head.
Rust 1.39.0 released
Rust 1.39.0 released
Rust 1.39.0 released
* Compile all functions as suspendable state machines: slow code because you can't leave values on the stack across a function call, you effectively have to allocate stack frames on the heap.
* Compile all functions as normal code: every suspendable computation has to have its own stack, i.e. fibers. See http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2018/p... for some of the problems there.
* Try to make the compiler detect which functions definitely can't (indirectly) suspend, compile those functions as normal code, use state machines for the rest: totally fails due to separate compilation, FFI, the difficulties of interprocedural control-flow analysis with function pointers, etc.
Rust 1.39.0 released
Rust 1.39.0 released
Rust 1.39.0 released
Rust 1.39.0 released
"In contrast, in Rust, calling an async function does not do any scheduling in and of itself, which means that we can compose a complex nest of futures without incurring a per-future cost. As an end-user, though, the main thing you'll notice is that futures feel "lazy": they don't do anything until you await them."
Rust 1.39.0 released