Live data from Hacker News

Async-await on stable Rust

blog.rust-lang.org

341–350 of 392 posts

Re: Async-await on stable Rust

#341
post #98

This is a big improvement, however this is still explicit/userland asynchronous programming: If anything down the callstack is synchronous, it blocks everything. This requires every components of a program, including every dependency, to be specifically designed for this kind of concurency. Async I/O gives awesome performance, but further abstractions would make it easier and less risky to use. Designing everything a…

> Async I/O gives awesome performance No, it doesn't really. 'Async' is a strictly Python problem, due to the insanity of the GIL. Predictably, the Python solution to it is also insane. Why you have to turn a sane language like Rust into an insane one by cargo-culting a solution to a non-problem is a mystery to me. Oh well, good thing at least C++ hasn't dropped the ball.

It’s important to distinguish 3 categories of coroutine implementations: stackful, stackless-on-heap, stackless-as-struct. C++ is stackless-on-heap. Stackless-as-struct is essentially creating an anonymous type (ala lambda), used to save the data across suspension points. This is the approach taken by Rust for its async/await implementation. I believe there were declaration/definition and ABI concerns about this approach for C++:

> "While it is theoretically not an insurmountable challenge , it might be a major re-engineering effort to the front-end structure and experts on two compiler front ends (Clang, EDG) have indicated that this is not a practical approach."

So the short answer seems to be that due to technical debt on the part of existing C++ compilers and their "straight" pipeline, the front-end cannot anticipate the size necessary for some book-keeping information traditionally handled by the code-generator. I'll take Richard Smith's word on Clang.

Re: Async-await on stable Rust

#342

Rust beginner here who writes a lot of async code in Node.js. If I am to start writing async code in Rust, should I directly pick up async-await? Or should I first understand how it is done in the current way?

You should start with async-await, but know that the ecosystem is in the middle of catching up, and so you may run into packages that are more awkward to use at the moment.

Re: Async-await on stable Rust

#343

Earlier quoted context omitted.

Yes this is amazing! And refactoring is actually quit easy to my experience, with two projects I've done this with at least.

I think it's straightforward, but it took me quite a while to do correctly in my dns project.

Are there any lessons that would be useful for others to know about?

Re: Async-await on stable Rust

#344

Earlier quoted context omitted.

I would say Ada/SPARK gets a lot of things right, too. What it lacks is hype and thus, a vibrant ecosystem. It can be a huge deal-breaker to many people.

Ada does have a good ecosystem and community, just not what we'd call modern and mainstream. I looked specifically at Ada, and for my use case macros are quite important. If I were to use Ada, I would need a separate code gen step. I also need concurrency without making new threads. I know Ada can do async but it doesn't have something like tokio. A shame. I wanted to give Ada a try, but didn't get very far before lo…

Have you taken a look at D? It might be what you're looking for. Although I wouldn't consider it mainstream.

Re: Async-await on stable Rust

#345
post #265

Earlier quoted context omitted.

Join doesn't do everything. It's just a way to take multiple futures, and return a Future wrapping them all. I think there's a misunderstanding of how Futures and Executors interact in rust here which is why everyone is having a hard time understanding things. A future in rust is really just a trait that implements a `poll` function, whose return type is either "Pending" or "Ready ". When you create a future, you're…

This is essentially what I assumed and what I believe what ralusek assumes to be the case. This does not change our question. What would be the syntax for how you would spawn a future, add it to the current Executor, cooperatively yield execution in the parent such that progress could be made on the child, but also return execution to the parent if the child yields but does not complete? In C# I believe you could sim…

It's the same. :)

    use std::time::Duration;
    use async_std::task;
    
    let shortTask = task::spawn(task::sleep(Duration::from_secs(1)));
    let longTask = task::spawn(task::sleep(Duration::from_secs(2)));

    task::sleep(Duration::from_secs(5)).await;
    shortTask.await;
    longTask.await;
or simply:

    futures.join!(
        task::sleep(Duration::from_secs(1),
        task::sleep(Duration::from_secs(2),
        task::sleep(Duration::from_secs(5)
    ).await;

Re: Async-await on stable Rust

#346

Earlier quoted context omitted.

All 5 of his points seem to be 2015 Javascript only. Some of them don't even apply to modern Javascript; I don't see any that apply to rust.

While I'm happy to believe you, with a short comment like that I just have to take your word for it. Could give a short explanation of how Rust already addresses each of these points for those of us who don't program in it?

This article is 90% a rant against “callback hell” that js was facing before async/await was introduced. The remaining 10% stays valid even in the presence of async/await, but the trade-off (ignored by the article) of the alternative is having to manually deal with synchronization primitives (at least channels), which would make zero sense given that JavaScript is a single-threaded environment.

Rust is a different beast, you can have whichever model you like best (OS threads, M:N threads (with third party libs), async/await) but async/await is by far the most powerful, that's why it's such a big deal that it lands on Rust stable.

Re: Async-await on stable Rust

#347

Earlier quoted context omitted.

Or maybe there are just a lot of people who like using rust because it fits their use cases very well and are excited about the release of a big new feature that’s been in development for a long time?

>...because it fits their use cases very well and are excited about the release of a big new feature. a bit too excited. GP isn't wrong, Go pretty much has the same thing and I have never seen so much fanboyism for a single feature ever in my career. I don't get it, but that might be because I am a manager.

It's not confusing because you're a manager but because you're a manager who doesn't understand the tools used to create the things by the people you're managing. You don't need to know how to do everything they do but you ought to know the importance of major upgrades in the tool set.

Re: Async-await on stable Rust

#348
post #62

This is a major milestone for Rust usability and developer productivity. It was really hard to build asynchronous code until now. You had to clone objects used within futures. You had to chain asynchronous calls together. You had to bend over backwards to support conditional returns. Error messages weren't very explanatory. You had limited access to documentation and tutorials to figure everything out. It was a proce…

So I guess the Generic Associated Types should be the next then?

I was trying to refactor one of my Rust project the other day and almost immediately got hit by the "No async fn in traits" and the "No lifetime on Associated Type" truck. Then few days later, comes this article: https://news.ycombinator.com/item?id=21367691.

If GAT can resolve those two problems, then I guess I'll just add that to my wish list. Hope the Rust team keep up the awesome good work :)

Re: Async-await on stable Rust

#349
post #317

Earlier quoted context omitted.

Afaik Rust's futures compile to a state machine, which is basically just a struct that contains the current state flag and the variables that need to be kept across yield points. An executor owns a list of such structs/futures and executes them however it sees fit (single-threaded, multi-threaded, ...). So there is no stack per future. The number of stacks depends on how many threads the executor runs in parallel.

> the current state flag the variables that need to be kept across yield points. you mean like... a stack frame?

Like a stack frame, but allocated once of a fixed size, instead of being LIFO allocated in a reserved region (which itself must be allocated upfront, when you don't know how big you're going to end up).

The difference being: if your tasks need 192B of memory each, and you spawn 10 of each, you just consumed a little less than 2kB. With green threads, you have 10 times the starting size of your stack (generally a few kB). That makes a big difference if you don't have much memory.

Re: Async-await on stable Rust

#350

Earlier quoted context omitted.

because of syntactical restrictions of how await work, at most you need to allocate a single function frame, never a full stack, and often it doesn't even need to be allocated separately and can live in the stack of the underlying OS thread.

So that async function cannot call anything else?

They can, but the function itself cannot be suspended by calling something else (i.e. await being a keyword enforces this), so any function that is called can use the original OS thread stack. Any called function can in turn be an async function, and will return a future[1] that in turn capture that function stack. So yes, a chain of suspended async functions sort of looks like a stack, but its size is known a compile time [2].

[1] I'm not familiar with rust semantics here, just making educated guesses.

[2] Not sure how rust deals with recursion in this case. I assume you get a compilation error because it will fail to deduce the return value of the function, and you'll have to explicitly box the future: the "stack" would then look a linked list of activation records.

Post reply on HN