Live data from Hacker News

Async-await on stable Rust

blog.rust-lang.org

21–30 of 392 posts

Re: Async-await on stable Rust

#22
I’ve been playing with async await in a polar opposite vertical than its typical use case (high tps web backends) and believe this was the missing piece to further unlock great ergonomic and productivity gains for system development: embedded no_std.

Async/await lets you write non-blocking, single-threaded but highly interweaved firmware/apps in allocation-free, single-threaded environments (bare-metal programming without an OS). The abstractions around stack snapshots allow seamless coroutines and I believe will make rust pretty much the easiest low-level platform to develop for.

Re: Async-await on stable Rust

#23
post #4

This is going to open the flood gates. I am sure lot of people were just waiting for this moment for Rust adoption. I for one was definitely in this boat. Also, this has all the goodness: open-source, high quality engineering, design in open, large contributors to a complex piece of software. Truly inspiring!

Maybe. I love Rust and use for all my work and hobby programming. With that said, I'm not in a super rush to use Async as it stands now. This is a foundational implementation and while you _can_ use it, you are also likely to run into a host of partially implemented support problems. No fault of anyone, just a lot left to do. Examples being, you may run into needing async FS ops, so you bring in one of those libs. Yo…

It's probably worth noting that an async scheduler (executor in Rust terms) is required for this to be useful, hard to write yourself, and not provided by the standard library.

There are crates that provide ready-made ones, and that will work for almost all cases, but it's another dependency that you have to evaluate and stay on top of.

It is entirely possible to do yourself, though. Last month, I dove into the details during a game jam. Not much of a game came out, but I did manage to get a useful async system up and running from scratch:

https://github.com/e2-71828/ld45/blob/master/doc.pdf (cf. Chapter 3)

Re: Async-await on stable Rust

#24
post #7

Earlier quoted context omitted.

Why would it be different for async code than sync code? The goal of Rust's checker is to track lifetime of an object so for example it knows that at the end of a function the object should be freed. Async shouldn't matter here.

The point is that Rust's borrow checker can't reason about lifetimes very well over function boundaries. It can reason about coarse things that are expressable in the type language, but everything more nuanced than that, such as reasoning about how control flow affects the lifetimes is limited to inside function bodies. The difference between synchronous code and async code implemented as libraries is that async code…

> The point is that Rust's borrow checker can't reason about lifetimes very well over function boundaries. It can reason about coarse things that are expressable in the type language, but everything more nuanced than that, such as reasoning about how control flow affects the lifetimes is limited to inside function bodies.

BTW this is a big pain point for me (unrelated to async). Code like this:

  let ref = &mut self.field;
  self.helper_mutating_another_field();
  do_something(ref);
gets rejected because self.helper_mutating_another_field() will mutably borrow the whole struct. The workaround is either to inline the helper or factor out a smaller substruct so that helper can borrow that which doesn't always look good.

Of course it is preferable that all information needed for the caller to check if the call is correct is contained in the function signature but it truly is frustrating to see the function body right there, know that it doesn't violate borrowing rules and still get the code calling it rejected.

Re: Async-await on stable Rust

#25
post #10

How does rust perform in parallel on the same memory? I heard it uses locks? This is not on the same memory right? https://news.ycombinator.com/item?id=21469295 If you want to do joint (on the same memory) parallel HTTP with Java I have a stable solution for you: https://github.com/tinspin/rupy

The same as any language, if you were to write safe code at least. By safe code I mean, if you wrote Go in such a way that race conditions could not happen, you typically would write it in the same way in Rust. Often this involves Mutexes, but there are plenty of libraries that set up foundations for parallel behavior without Mutexes.

So it can operate on "the same memory", and there are a whole lot of ways to manage it safely. The right tool for the right job, really.

Re: Async-await on stable Rust

#27
post #5

Earlier quoted context omitted.

Are there that many people looking for a new low level language for server side software?

Rust isn't only great because it's low level. Things like sum types (called enums in rust), pattern matching and expression orientation mean that it is often much more expressive than other languages for high level code.

ML-inspired languages have all these features too; is the advantage of Rust over those just that it’s more mainstream, the ecosystem is bigger, etc.?

Re: Async-await on stable Rust

#28
post #7

Earlier quoted context omitted.

Why would it be different for async code than sync code? The goal of Rust's checker is to track lifetime of an object so for example it knows that at the end of a function the object should be freed. Async shouldn't matter here.

In Rust, it is normally not possible or at least very difficult to create structs where one field references another, and if you were to create a future that borrows some field, awaits a future, and uses the borrowed field, the resulting future will need to have a field with a reference to another. This is the challenge and async await lets you make this kind of self referential types without unsafe code.

That's just the "Pin" type, which is heavily used in async code behind (and occasionally in front) the scenes, but is by no means restricted to it.

Re: Async-await on stable Rust

#29
post #23

Earlier quoted context omitted.

Maybe. I love Rust and use for all my work and hobby programming. With that said, I'm not in a super rush to use Async as it stands now. This is a foundational implementation and while you _can_ use it, you are also likely to run into a host of partially implemented support problems. No fault of anyone, just a lot left to do. Examples being, you may run into needing async FS ops, so you bring in one of those libs. Yo…

It's probably worth noting that an async scheduler (executor in Rust terms) is required for this to be useful, hard to write yourself, and not provided by the standard library. There are crates that provide ready-made ones, and that will work for almost all cases, but it's another dependency that you have to evaluate and stay on top of. It is entirely possible to do yourself, though. Last month, I dove into the detai…

Indeed.

On a semi-related note, any thoughts on how you could merge Async with non-Async code? Eg, I've got a large codebase that is not threaded but not Async. In the future, I might upgrade the web server to be Async and slowly start porting code.

I had planned/hoped that I could make my own Async/Thread bridge. Such that non-Async code would live in it's own thread, and I would make a special Future ask a Mutex in another thread if data is available. Taking special care not to lock the Future's thread.

The goal of course is to not have to rewrite the entire app's blocking code at once.

Does this sound stupid to you?

Re: Async-await on stable Rust

#30
Isn't it kind of a poor design choice that Rust will not actually begin execution of the function until `.await` is called? If I didn't want to execute the function yet, I wouldn't have invoked it. Awaiting is a completely different concept than invoking, why overload it?

If you want to defer execution of a promise until you await it, you can always do that, but this paradigm forces you to do that. The problem is then, how do I do parallel execution of asynchronous tasks?

In JavaScript I could do

   const results = await Promise.all([
     asyncTaskA(),
     asyncTaskB(),
     asyncTaskC()
   ]);
and those will execute simultaneously and await all results.

And that's me deferring execution to the point that I'd like to await it, but in JavaScript you could additionally do

   const results = await Promise.all([
     alreadyExecutingPromiseA,
     alreadyExecutingPromiseB,
     alreadyExecutingPromiseC
   ]);
Where I pass in the actual promises which have returned from having called the functions at some point previously.

So how is parallel execution handled in Rust?

Post reply on HN