Earlier quoted context omitted.
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,…
Asynchronous Programming in Rust book
41–46 of 46 posts
Re: Asynchronous Programming in Rust book
#42Earlier 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 )…
> 1. Make sure, manually(?), that all things are async / non-blocking.
You'd have to make sure any IO you do is using Futures - ie, use a package to provide async IO primitives for disk and network access. You would also need to use the appropriate await syntax call on any future using methods - that would require a bit of overhead to know, but at least the compiler has your back on that.
> 2. Implementing Future.poll / wrapping types in Future?
In most cases I don't think you'd have a use case to implement a Future - would you? Ie, main IO calls are the big ones for wasting threads - and libraries like mio/hyper/etc provide your IO primitives.
> 3. Async polution, a function that uses async must be async too?
Yea, my understanding is that this is definitely an issue. I am already planning on using `async` tags on basically all my functions, because everything I use bound to IO in one form or another.
On the bright side, I believe (don't quote me!) that you can drop ugly `fn foo() -> Futures>` wrapping, since I believe `async fn foo() -> Result` does the same thing. .. again, the syntax is not finalized haha.
> 4. Setup some scheduler that maintain how many concurrent async operations one thread has?
If you're using Async I'd imagine you'd already have chosen a scheduler. I believe Tokio will be the defacto - though Rayon might be involved here, not sure.
> 5. More verbose error-messages / stack-traces?
Errors themselves would be unaffected, if you're talking normal error values - remember those are just values in Rust, like Go, so not much special there.
Though as you said, I imagine if you dump a trace it would look different, no idea.
None of this post was meant to counter you in anyway. I just hoped to provide a bit of clarity on the tiny things I can contribute to. I hope I helped more than hurt. Have a nice day :)
Re: Asynchronous Programming in Rust book
#43Earlier quoted context omitted.
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,…
> Thought there was a limit for work that can be done concurrently by the CPU,
Right. But in an IO bound scenario, the CPU isn't doing work; it's waiting on IO. So, because threads are generally heavy, you don't want a ton of them, taking up memory, doing nothing.
But, when you have lightweight threads, you can spin up one per connection. This ends up being simpler, and you don't have the large memory usage. This is what nginx does, in a sense. It still has a worker per core, but each of those workers can handle thousands of requests simultaneously, because it's all non-blocking.
That limit to concurrent work is exactly why non-blocking architectures are so important, and task systems fit into them really nicely.
Re: Asynchronous Programming in Rust book
#44How much performance is gained by going async instead of blocking threads on modern hardware? Skimmed through https://vorner.github.io/async-bench.html . If I understand it correctly, one get about twice the performance with async. Is this correct? Seems like a compromise (code complexity vs performance) not worth taking.
Re: Asynchronous Programming in Rust book
#45Earlier quoted context omitted.
> 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,…
Okay so, there are lots of ways to do this kind of stuff. A threadpool is a pretty classic one. Apache being the poster child here in an HTTP server context. > Thought there was a limit for work that can be done concurrently by the CPU, Right. But in an IO bound scenario, the CPU isn't doing work; it's waiting on IO. So, because threads are generally heavy, you don't want a ton of them, taking up memory, doing nothin…
Re: Asynchronous Programming in Rust book
#46Earlier quoted context omitted.
> 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…
In hindsight, I prefer async/await. My reason is primarily that like your example points out, it really lets me be in full control over the scheduled behavior. I could even take non-io work and make it "async". Ie, some long processing application takes a break every million iterations to let other tasks steal some work. That's just cool!
Arguably a similar thing could be designed in Go if every million iterations you used some type of IO primitive, like sending some data over a channel, but the behavior of Rust's model is more fine grained.