Over time I've increasingly been impressed with mature implementations of threads (Java) and less impressed with async.
For a while I built small to medium applications w/ async python and had a lot of luck, but when the scope changed just a bit I found I was a lot better off with gunicorn, I'd probably be even better off with Java if the system didn't have a foot in the world of scikit-learn, huggingface and all that. (Mainly in batch jobs but what if I want to do a little inference when I do a web request?)
My understanding about Rust is that the borrowing mechanism works just fine with threads. since objects are naturally scoped to a sequence of operations that are written out into code (you go into a code block, that code block calls a function, that function calls a function, and things can be released as you unwind out)
In async now you usually wind up with something like the continuation passing style, function A gets called by the event loop and creates an object, many other functions get run by the event loop, some of which might use that object, then finally function X gets run and tears the object down. "The event loop owns the object" is an answer but not very satisfying, a general answer gives the event loop the responsibilities of the garbage collector.
I think people don't really get how revolutionary the garbage collector is. You can smack together two arbitrary Java libraries and not worry about memory management because the runtime handles memory management.
I agree 100%. Virtual threads have drawn a lot of skepticism but even Rust once had a version with them. They enable the strong structuted concurrency patterns. Async/await works nicely as long as your use case is "do this work on another thread, free this one up, resume here when the async task is done", but I've found that to be most common in UI work, and still not all that common (like if you want to track its progress, you still got some async state management coding to do). And even then you end up with a function coloring problem. People can try to downplay that, bit it is a giant wart resulting from that approach. I'll take Java's virtual threads combined with their structured concurrency efforts over async/await almost every time.
For a while I built small to medium applications w/ async python and had a lot of luck, but when the scope changed just a bit I found I was a lot better off with gunicorn, I'd probably be even better off with Java if the system didn't have a foot in the world of scikit-learn, huggingface and all that. (Mainly in batch jobs but what if I want to do a little inference when I do a web request?)
My understanding about Rust is that the borrowing mechanism works just fine with threads. since objects are naturally scoped to a sequence of operations that are written out into code (you go into a code block, that code block calls a function, that function calls a function, and things can be released as you unwind out)
In async now you usually wind up with something like the continuation passing style, function A gets called by the event loop and creates an object, many other functions get run by the event loop, some of which might use that object, then finally function X gets run and tears the object down. "The event loop owns the object" is an answer but not very satisfying, a general answer gives the event loop the responsibilities of the garbage collector.
I think people don't really get how revolutionary the garbage collector is. You can smack together two arbitrary Java libraries and not worry about memory management because the runtime handles memory management.