But I do agree that it seems that people jump to use async instead of e.g. threads. I think there should be more literature around what situations work best for threads vs async, etc.
But I do agree that it seems that people jump to use async instead of e.g. threads. I think there should be more literature around what situations work best for threads vs async, etc.
Then again, few programs are actually single-tasked in practice, and libraries often end up taking advantage of those async primitives for doing stuff like connection pooling even if your application code doesn't see it.
thing1_promise = get_thing(1)
thing2_promise = get_thing(2)
thing1 = thing1_promise.await
thing2 = thing1_promise.await
is almost always more difficult to do with threads. Sure, some threading APIs support joining nicely but it tends to be more awkward. Especially if you want to do something like handle the first request to finish first.Also the startup cost of threads affects how you write code. Does your library spawn a new thread for every HTTP request? Probably not, it is expensive and the server may be on the same host. So you end up with less consistent async support. Since async programming is a lot cheaper you tend to see better support which adds up.
Thus you only pay for it if it is required.
Minimal-cost threading support requires taking Send + Sync into account, essentially thread-safety: and the thread-safe primitives are more expensive than the thread-local primitives. Send + Sync matters become pervasive through the design of threaded code, even if they don’t need to be spelled out most of the time.
Minimal-cost async requires compiling the code into a state machine, which means you’ve got to restrict borrowing across suspend points, or mess around with Pin.
Threading and async are quite different in a language like Rust. They can even play quite nicely together. But you really can’t unify them.
Sure, you could do simple cases like single-threaded blocking-or-async, e.g. `async? fn foo() { bar().await; }` compiling to something like strawman `fn sync#foo() { sync#bar(); } async fn async#foo() { async#bar().await; }`, but this falls apart completely as soon as you want to do anything beyond immediate .await.
I guess I'm glad that Rust developers don't design CPUs, as we wouldn't have memory abstractions like cache coherent NUMA (which doesn't come for free).
Case in point: a CPU plus a discrete GPU is technically a NUMA system, and low-level APIs like Vulkan explicitly expose the ability to allocate non-coherent memory. I strongly assume that accessing that memory doesn't incur coherency overhead.
What are you even talking about? Rust gives you plenty of choice, it even lets you create as many "non-free" abstractions as you'd like.
As another example: compare "GC'd versus non-GC'd memory in Rust" to "coherent versus non-coherent memory in CPU architecture"; here Rust gives us just the bare machine, while CPU architects give us quite some abstraction plus a choice.
It is true that you could theoretically write a GC in Rust, but using it from the language itself would probably break ergonomics so much that you'd be better off with another language.
The only way to run code in another Thread is by spawning an `Isolate`. But once you have one, you can expose an API that is indistinguishable from an usual async one.
And the Dart 2.15 announcement (latest version as of today), which had a focus on making Isolates fast: https://medium.com/dartlang/dart-2-15-7e7a598e508a
EDIT: the main article about concurrency in Dart is actually this one: https://dart.dev/guides/language/concurrency
Try `dart compile exe app.dart` and then run `./app.exe`... it's really fast and the binary is fairly small!
The installation process is simple, documentation is excellent, the core library makes sense, the defacto package repository and package management is clean. And WRT this thread, the async model is dead simple to pick up.
As a scripting language it seems to be a perfect fit. But there is also a lot of first rate tooling available for Dart and I am starting to wonder if it wouldn’t be a good choice for larger projects as well.