3 ms·
I would be very interested in hearing from experienced folks about how important this is/what useful patterns it unlocks. I ask because I remember when trying
by davidatbu 4y ago
I would be very interested in hearing from experienced folks about how important this is/what useful patterns it unlocks.
I ask because I remember when trying to learn Kotlin, the docs made a big deal of structured concurrency[0], and golang of course is known for its concurrency story.
[0] https://kotlinlang.org/docs/coroutines-basics.html#structured-concurrency https://kotlinlang.org/docs/coroutines-basics.html#structure...
- masklinn 4y ago> I would be very interested in hearing from experienced folks about how important this is/what useful patterns it unlocks. For Rust it allows thread to play better with lifetimes, which means there are scenarios where you don’t need the overhead of a lock (and usually the Arc that does with it, unless you go with a global) or queue, you can just work with on-stack “unsynchronised” borrows and it’s thread safe. That means lower syntactic and runtime overhead in the cases where it’s an option. It was already available in crossbeam so it’s not novel novel, but not needing a dependency for it is useful still.
- davidatbu 4y agoThanks! I didn't know that it was already available in crossbeam, that helps a lot in understanding the significance of this feature.
- klabb3 4y agoSadly, this is only lexical scoping which means you can only borrow from the outer scope and not ad-hoc the normal way borrowing works in Rust. In short, this means that thread pools and async runtimes cannot use this feature to provide borrowing across tasks. We're still stuck with Arc-ing everything that crosses task boundaries. Prior to 1.0, there were "true" scoped threads (with a lifetime 'a on the join handle), which let you borrow from the parent thread. (This could have extended to tasks as well, had they been around.) unfortunately it wasn't safe together with the much more popular Arc/Rc, which wasn't 'static restricted, despite it's ability to cause cycles and leak. So those powerful scoped threads were removed and "destructors are not guaranteed to run in safe Rust" was formalized instead. Seeing how popular async became, I wonder if this was the only and right way to move forward. I'm not against Arcs, they have their place. But if you can use normal RAII it's much preferable.
- oconnor663 4y ago> async runtimes cannot use this feature to provide borrowing across tasks They can't use this function, but with some duplicated unsafe code they can still provide similar APIs for their callers, right? Things like this: https://github.com/jaboatman/tokio-scoped https://github.com/jaboatman/tokio-scoped
- thramp 4y agothe problem with this approaches like these that it requires blocking the runtime: https://github.com/jaboatman/tokio-scoped/blob/master/src/lib.rs#L229-L231 https://github.com/jaboatman/tokio-scoped/blob/master/src/li....
- klabb3 4y agoI just checked quickly so may be wrong, but it looks like they're pulling the same trick as with the new scoped threads, ie only lexical scoping. Note also that the scope function is blocking and called from within an async fn, which is normally not great for composability with other async code. That said, taking a step back it has crossed my mind that bringing back true scoping with unsafe in the impl might be an acceptable way forward, despite how upsetting this is to a lot of rustaceans. I think that the failure modes (ie triggering UB) for this case can be simply enumerated in a short list of "DON'Ts" (such as putting a scoped join handle in an Arc). OTOH, since leaking was formalized and explicitly allowed (heck, even borderline encouraged through mem::forget), god knows if people have exploited that for other cases in true Hyrum's law fashion, that breaks the abovementioned idea. They certainly had the right to.
- GolDDranks 4y agoHow is this different from the prior 1.0 scoped threads? I remember the whole "Leakpocalypse" event that lead to the deletion of the API, (and subsequently, to invention of this API, where the scope guard is represented as an additional closure) but those were entirely lexical too, right? Rust borrows in general are pretty much lexical in the sense that you only analyze the body local function, nothing more. Rustc can't reason about dynamic invariants, you need runtime checks for that.