4 ms·
I think the pain you went through with Java is not quite compareable, as the described havoc (and I do really feel your pain here) would not happen like that in
by gr__or 6y ago
I think the pain you went through with Java is not quite compareable, as the described havoc (and I do really feel your pain here) would not happen like that in Rust, for the reason that you would have to model these things more explicitly. In detail, it sounds like a cascade of implicit null-ness (aka the billion dollar mistake) and weak references. In Rust null (called None) is explicit through the Option type and the Weak type returns exactly that.
More to your point, as I think you were using this as an analogy for the perils of giving up control: Rust's explicitness should entail all the semantics of your program, and hence async Rust makes you model out all the potentially-racy async interactions with Arc, Mutex, etc. The same middle-man (the borrow checker) who watches over your regular ol' sync code's memory-correctness, now expects extra constraints to be upheld for values passing through async-boundaries. And for me the whole point of Rust is that this correctness proof will do a better job than any person could, for any moderately sized program. So this is middle man you'd want between you and the CPU.
That said, your async runtime could definitely do shenanigans that screw up your nicely modeled program, but that would be a bug in that specific runtime. I haven't deeply read Tokio's source and even if I did, making a qualified judgment about it is beyond me.
- skohan 6y agoSo I would not say that the borrow checker is a middle-man. The borrow checker does impose constraints on programming, but at the end of the day it's only relevant at compile time, and you still end up with code which maps in a predictable way to the hardware. If you hand me a synchronous rust code, I can imagine, at least in some approximate way, which set of assembly code would be equivalent. An async runtime is a totally different animal. If you hand me a block of async rust code and ask me how it will execute, the answer I have to give is "it depends on the runtime". This is the disconnect I am talking about.
- gr__or 6y agoFair distinction, thanks for making it! My async use cases so far have been in a realm where everything modeled was everything I cared about, and those specifics of the runtime didn't become relevant. I wanted to refer to your example because I do see how that is a thing that needs to be explicitly modeled. I'd be curious to hear about examples where the runtime did or would surprise you!
- skohan 6y agoI don't have a ton of experience writing async rust programs, but I can imagine some types of problems which might come up: - So what if I am implementing a high-throughput, performance critical system which makes heavy use of async, and under certain circumstances the runtime I'm using falls off a performance cliff. It's going to be difficult to diagnose and solve this problem, because the critical path of my program actually winds through a library which is essentially a black box to me. - What if I have two dependencies, and each one internally depends on a separate async runtime. And what if each of these runtimes is designed with the assumption that it is the main owner of system resources, like threads. There may be conflicts which are very difficult to understand but have effects on the performance of my program. I think fundamentally, an issue with this type of "middleware" is that by its nature, an async runtime, like Tokio for example, has to be implemented with a lot of assumptions about how "the generic program" should optimally handle async. It may work great for the vast majority of use-cases, but fundamentally whenever you design a super general, abstract system like this you have to make tradeoffs. In some ways Rust has taken probably the best possible approach to this, by making it modular and allowing you to bring your own runtime, but I think in practice, if the use of async continues to become pervasive in Rust and certain libraries get locked into certain ecosystems, it will not be so easy in practice to take advantage of that modularity.