Earlier quoted context omitted.
The ideas that have been batted around is called "async drop" [1] And it looks like it's still just an unaddressed well known problem [2]. Honestly, once the Mozilla sackening of rust devs happened it seems like the language has been practically rudderless. The RFC system seems almost dead as a lot of the main contributors are no longer working on rust. This initiative hasn't had motion since 2021. [3] [1] https://ru…
Those pages are out of date, and AsyncDrop is in progress: https://github.com/rust-lang/rust/issues/126482 I think "practically rudderless" here is fairly misinformed and a little harmful/rude to all the folks doing tons of great work still. It's a shame there are some stale pages around and so on, but they're not good measures of the state of the project or ecosystem. The problem of holding objects across async poin…
Futurelock: A subtle risk in async Rust
21–30 of 251 posts
Re: Futurelock: A subtle risk in async Rust
#22Earlier quoted context omitted.
Not a Rust designer, but a big motivation for Rust's async design was wanting it to work on embedded, meaning no malloc and no threads. This unfortunately precludes the vast majority of the design space here, from active futures as seen in JS/C#/Go to the actor model. You can write code using the actor model with Tokio. But it's not natural to do so.
As a curious bystander, it will be interesting to see how the Zig async implementation pans out. They have the advantage of getting to see the pitfalls of those that have come before. Getting back to Rust, even if not natural, I agree with the parent that the actor model is simply the better paradigm. Zero runtime allocation should still be possible, you just have to accept some constraints. I think async looks simpl…
Re: Futurelock: A subtle risk in async Rust
#23Earlier quoted context omitted.
The ideas that have been batted around is called "async drop" [1] And it looks like it's still just an unaddressed well known problem [2]. Honestly, once the Mozilla sackening of rust devs happened it seems like the language has been practically rudderless. The RFC system seems almost dead as a lot of the main contributors are no longer working on rust. This initiative hasn't had motion since 2021. [3] [1] https://ru…
Those pages are out of date, and AsyncDrop is in progress: https://github.com/rust-lang/rust/issues/126482 I think "practically rudderless" here is fairly misinformed and a little harmful/rude to all the folks doing tons of great work still. It's a shame there are some stale pages around and so on, but they're not good measures of the state of the project or ecosystem. The problem of holding objects across async poin…
That great work is mostly opaque on the outside.
What's been noticeable as an observer is that a lot of the well known names associated with rust no longer work on it and there's been a large amount of turnover around it.
That manifests in things like this case where work was in progress up until ~2021 and then was ultimately backburnered while the entire org was reshuffled. (I'd note the dates on the MCP as Feb 2024).
I can't tell exactly how much work or what direction it went in from 2021 to 2024 but it does look apparent that the work ultimately got shifted between multiple individuals.
I hope rust is in a better spot. But I also don't think I was being unfair in pointing out how much momentum got wrecked when Mozilla pulled support.
Re: Futurelock: A subtle risk in async Rust
#24Earlier quoted context omitted.
Not a Rust designer, but a big motivation for Rust's async design was wanting it to work on embedded, meaning no malloc and no threads. This unfortunately precludes the vast majority of the design space here, from active futures as seen in JS/C#/Go to the actor model. You can write code using the actor model with Tokio. But it's not natural to do so.
> But it's not natural to do so. I tend to write most of my async Rust following the actor model and I find it natural. Alice Rhyl, a prominent Tokio contributor, has written about the specific patterns: https://ryhl.io/blog/actors-with-tokio/
Re: Futurelock: A subtle risk in async Rust
#25Re: Futurelock: A subtle risk in async Rust
#26Earlier quoted context omitted.
_an answer_ is performance - the necessity of creating copyable/copied messages for inter-actor communication everywhere in the program _can be_ expensive. that said there are a lot of parts of a lot of programs where a fully inlined and shake optimized async state machine isn't so critical. it's reasonable to want a mix, to use async which can be heavily compiler optimized for performance sensitive paths, and use hi…
I’m not sure this is actually true? Do messages have to be copied?
in a single threaded fully cooperative environment you could ensure this by implication of only one coroutine running at a time, removing data races, but retaining logical ones.
if you want to eradicate logical races, or have actual parallel computation, then the source data must be copied into the message, or the content of the message be wrapped in a lock or similar.
in almost all practical scenarios this means the data source copies data into messages.
Re: Futurelock: A subtle risk in async Rust
#27- wrong -
> In this case, what’s dropped is &mut future1. But future1 is not dropped, so the actual future is not cancelled.
Re: Futurelock: A subtle risk in async Rust
#28- wrong -
Re: Futurelock: A subtle risk in async Rust
#29Great read, and the example code makes sense. This stuff can be a nightmare to find, but once you do it's like a giant 1000 piece puzzle just clicks together instantly.
We are (on brand?) going to do a podcast episode on this on Monday[1]; ahead of that conversation I'm going to get a clip of that video out, just because it's interesting to see the team work together to debug it.
Re: Futurelock: A subtle risk in async Rust
#30The OS can detect this and make T_low "inherit" the priority of T_high. I wonder if there is a similar idea possible with tokio? E.g. if you are awaiting a Mutex held by a future that "can't run", then poll that future instead. I would guess detecting the "can't run" case would require quite a bit of overhead, but maybe it can be done.
I think an especially difficult factor is that you don't even need to use a direct await.
let future1 = do_async_thing("op1", lock.clone()).boxed();
tokio::select! {
_ = &mut future1 => {
println!("do_stuff: arm1 future finished");
}
_ = sleep(Duration::from_millis(500)) => {
// No .await, but both will futurelock on future1.
tokio::select! {
_ = do_async_thing("op2", lock.clone()) => {},
_ = do_async_thing("op3", lock.clone()) => {},
};
}
};
I.e. so "can't run" detector needs to determine that no other task will run the future, and the future isn't in the current set of things being polled by this task.