Live data from Hacker News

Asynchronous Programming in Rust book

rust-lang.github.io

31–40 of 46 posts

Re: Asynchronous Programming in Rust book

#31
post #27

Earlier quoted context omitted.

Not to over simplify, but when you say code complexity, are you referring to the code you read? Like, the dev UX? If so, I'd argue that long term once async/await have landed properly, the code largely looks and behaves the same. With that said, I've not even used it yet, because I've got no clue when this is landing enough that I can reasonably use it.. and I'm on Nightly lol.

> are you referring to the code you read? Yes, the code the developer needs to read, write and understand. I'm not familiar of how async/await will be in Rust, but I guess some code differences/complexities can be: 1. Make sure, manually(?), that all things are async / non-blocking. 2. Implementing Future.poll / wrapping types in Future? (What is Pin? ref https://rust-lang.github.io/async-book/execution/future.html )…

> 3. Async polution, a function that uses async must be async too?

Coming from JS, that's a non-problem in Rust. You can easily make a function blocking by creating a event loop and resolving the future you get from another function in it. So when I refactor my code to be async, I'm starting by making a single function async, and the moving the event loop from function to function, until as much of the code is async as I want.

Re: Asynchronous Programming in Rust book

#32
post #29

Earlier quoted context omitted.

> but has other advantages, like reduced resource consumption Could you expand on that? I've never heard that mentioned about async before.

You can think of a task as being a thread, but it has one single allocation that’s the exact possible stack size. No more, no less. This uses less memory than spinning up a thread with the default stack size. Yes, you could use the proper APIs and get the correct size too, but you have to figure that size out by hand for each thread. It just implicitly happens with tasks.

Huh, I didn't know that!

(I also misinterpreted the context as I read the top level comment as async vs a single thread with blocking code, but after rereading it that makes more sense.)

Re: Asynchronous Programming in Rust book

#33
post #32

Earlier quoted context omitted.

You can think of a task as being a thread, but it has one single allocation that’s the exact possible stack size. No more, no less. This uses less memory than spinning up a thread with the default stack size. Yes, you could use the proper APIs and get the correct size too, but you have to figure that size out by hand for each thread. It just implicitly happens with tasks.

Huh, I didn't know that! (I also misinterpreted the context as I read the top level comment as async vs a single thread with blocking code, but after rereading it that makes more sense.)

It's all good; it's one of the things that's specific to our implementation. Other forms may or may not do this, but I'm pretty sure that it's novel to at least Rust, and maybe C++; there's some discussion that I think it can do this in some circumstances as well.

Re: Asynchronous Programming in Rust book

#34
post #29

Earlier quoted context omitted.

> but has other advantages, like reduced resource consumption Could you expand on that? I've never heard that mentioned about async before.

You can think of a task as being a thread, but it has one single allocation that’s the exact possible stack size. No more, no less. This uses less memory than spinning up a thread with the default stack size. Yes, you could use the proper APIs and get the correct size too, but you have to figure that size out by hand for each thread. It just implicitly happens with tasks.

Default stack size for new threads is 2 MB, https://doc.rust-lang.org/std/thread/#stack-size. That means total_memory_usage = 2 MB * number_of_cores, which is not so much on modern hardware.

Re: Asynchronous Programming in Rust book

#35
post #34

Earlier quoted context omitted.

You can think of a task as being a thread, but it has one single allocation that’s the exact possible stack size. No more, no less. This uses less memory than spinning up a thread with the default stack size. Yes, you could use the proper APIs and get the correct size too, but you have to figure that size out by hand for each thread. It just implicitly happens with tasks.

Default stack size for new threads is 2 MB, https://doc.rust-lang.org/std/thread/#stack-size . That means total_memory_usage = 2 MB * number_of_cores, which is not so much on modern hardware.

...and of course you know that, being on the Rust core team, just adding the specifics (I did not know the numbers myself).

Re: Asynchronous Programming in Rust book

#36
post #5

There isn't too much activity on this book [1] but I definitely think that more documentation about async programming in Rust is needed. Just recently I wanted to do something in async Rust and it's just such a PITA. I'm writing Rust since 3-4 years now and async throws me back to those first days where I didn't know how to cope with the error messages. Hopefully async/await syntax will improve this experience, but e…

Hi, you might be interested in a crate I wrote called desync: https://docs.rs/desync/0.3.0/desync/ - it provides a very simple yet expressive API for performing asynchronous operations and has full support for the futures crate. It can be learned really quickly.

Desync takes a slightly different approach to asynchronous programming: instead of being based around the idea of scheduling operations on threads, and then synchronising data across those threads, it's based on the idea of scheduling operations on data.

There's only two basic operations: 'desync' runs an operation on some data in the background, and 'sync' runs one synchronously.

All operations are run in order and 'sync' returns a value so it's a way to retrieve data from an asynchronous operation. It's sort of like setting up some threads with some data protected by a mutex and sending results between them using mpsc channels, except without the need to build any of the scaffolding. ('sync' also makes borrowing data from one task to use in another effortless)

Re: Asynchronous Programming in Rust book

#37
post #35
post #34

Earlier quoted context omitted.

Default stack size for new threads is 2 MB, https://doc.rust-lang.org/std/thread/#stack-size . That means total_memory_usage = 2 MB * number_of_cores, which is not so much on modern hardware.

...and of course you know that, being on the Rust core team, just adding the specifics (I did not know the numbers myself).

Hm, maybe I misunderstand what you're getting at; you're talking about one thread per core, not one thread per unit of work? Sure, if you only have that few threads, then it's not that big of a difference, but if you want to spin up a few hundred thousand of them...

Re: Asynchronous Programming in Rust book

#38
post #11

This approach to async programming feels like a much more leaky abstraction than the 'it's basically semaphores' stuff for m:n threads. Though being able to do so much as a library is nice. How does async translate calls to other async functions? Is refactoring into smaller async functions less efficient? If not, how does it deal with (possibly indirect) recursive function calls? Does it give up or select a loop brea…

> How does async translate calls to other async functions? There's nothing special going on. Remember, async on a function is something like async fn function(argument: &str) -> usize { to fn function(argument: &str) -> impl Future { so, when you call an async function, you get a Future back. That's true even if it's inside of another async function. > If not, how does it deal with (possibly indirect) recursive funct…

Thanks for your answers!

From the second blog post I actually found https://github.com/tokio-rs/tokio/pull/660 which switched tokio from 1 reactor+worker threads to n reactors with work stealing.

Re: Asynchronous Programming in Rust book

#39
post #29

Earlier quoted context omitted.

async isn't only about performance, but has other advantages, like reduced resource consumption. In addition to that async io also gives you better control over how to cancel io reads and writes on systems where the IO is not interruptible. But you are correct, if you don't have a specific need, async is generally harder than using threads for concurrency. Ideally the async/await work in Rust is going to make that tr…

> but has other advantages, like reduced resource consumption Could you expand on that? I've never heard that mentioned about async before.

A fun example is the slow loris attack. You send your requests character by character with 20+ seconds between packets. For mobile 20 seconds can happen so if the server doesn't use a running window to check timeouts it can't kill the connection.

Now you do this 1000 times you use barely any resources but the server uses 1GB in stack allocations which might be the maximum and noone else can connect.

https://en.wikipedia.org/wiki/Slowloris_(computer_security)

Re: Asynchronous Programming in Rust book

#40
post #35

Earlier quoted context omitted.

...and of course you know that, being on the Rust core team, just adding the specifics (I did not know the numbers myself).

Hm, maybe I misunderstand what you're getting at; you're talking about one thread per core, not one thread per unit of work? Sure, if you only have that few threads, then it's not that big of a difference, but if you want to spin up a few hundred thousand of them...

> you're talking about one thread per core, not one thread per unit of work?

Yes, a thread pool, consisting of one thread per core/computing unit. The units of work are then scheduled between the threads. Units of work here being some kind of IO, e.g. servicing HTTP requests.

> but if you want to spin up a few hundred thousand of them...

Hm. Thought there was a limit for work that can be done concurrently by the CPU, based on the number of cores/hyper-threads available. Found this on threads and IO performance [1], it seems to make the same point.

What kind of work load is common to spread over so many threads (on the same machine)? Does the OS switch efficiently between hundred of threads on regular CPUs? Genuinely interested.

1: https://www.jstorimer.com/blogs/workingwithcode/7970125-how-...

Post reply on HN