| > Once you write enough code, you'll realize you need synchronization primitives for async code as well. In pretty much the same cases as threaded code. I've been programming for 30 years, including over a decade in JS. You need sync primitives in JS sometimes, but they're trivial to write in javascript because the code is run single threaded and there's no preemption. > What you're trying to do may require IO Its usually possible to factor your code in a way that separates business logic and IO. Then you can make your business logic all completely synchronous. Interleaving IO and logic is a code smell. > The Promise static methods (any, all, race, etc) are particularly useful. But, you could implement that for threads. I believe that this convenience difference is more due to modernity, of the threading model being, what 40, 50, 60 years old, and given a clean-ish slate to build a new model, modern language designers did better. Then why don't see any better designs amongst modern languages? New languages have an opportunity to add newer, better threading primitives. Yet, its almost always the same stuff: Atomics, mutexes and semaphores. Even Rust uses the same primitives, just with a borrow checker this time. Arguably message passing (erlang, go) is better. But Go still has shared mutable memory and mutexes in its sync library. > But it raises the idea: if we rethought OS-level preemptible concurrency today (don't call it threads!), could we modernize it and do better even than async? I'd love to see some thought put into this. Threading doesn't seem like a winner to me. |
> Multithreaded code is often much harder to reason about than async code, because threads can interleave executions and threads can be preempted anywhere.
No, green threads / fibres or whatever you want to call them explicitly don't interleave executions. They are a form of cooperative multitasking. Async/await is another form of co-operative multitasking. One former just builds on what we already have. The latter re-invents the universe.
By the by, the blocker for Javascript green threads wasn't preemption, mostly because there isn't any. It's that Javascript has a "run to completion" model. If the DOM calls a javascript event (which is effectively how all javascript is invoked in a browser), it doesn't block, so it always runs to completion. Green threads break that model. It's not a insurmountable break - the DOM events could always still return immediately, but they could start a green thread that returns to them as soon as they block. Thinking about it, the change is possibly smaller than language changes required by async/await.
If you can reason about where an await is, you can reason about where a green thread yields. The only difference is that one of them clutters your syntax and the other doesn't.