Top
Best
New

Posted by willm 9/2/2025

Python has had async for 10 years – why isn't it more popular?(tonybaloney.github.io)
324 points | 295 commentspage 5
nurettin 9/3/2025|
Python async feels great ergonomically at first. Async tasks, timers, things happening concurrently. But then you lose stack traces. Code that starts sync, then appends jobs to an async event queue can't be traced, because the exception happened in the loop and doesn't bubble up to sync (or it didn't back in 3.8). That, among with synchronization problems (it is an event loop, why do we even need to synchronize? async mutex??)

I really tried to make it work, but eventually gave up and went back to deque. Now life is great.

the__alchemist 9/2/2025||
The barrier it places in Rust's lib ecosystem is unpleasant; I'm glad it hasn't taken off in Python. I have written too many rust libs because the existing ones forced your code to be Async.
bigstrat2003 9/3/2025|
The bifurcation of the Rust ecosystem due to async makes me absolutely loathe the feature, and wish it had never been added to the language. It's so awful.
lormayna 9/2/2025||
I always considered the ergonomic of async/await not really ergonomical and hard to debug. I really like, indeed, the go approach: using goroutines, channels and waitgroups is powerful and easy.
matthew16550 9/3/2025||
Pythons builtin async always confuses me.

The Trio library felt easy to learn and just worked without much fuss.

https://trio.readthedocs.io/

omnicognate 9/2/2025||
For a counter-opinion that isn't getting stated much here, I think:

* Asyncio is pretty good, and is usually the best choice for non-blocking I/O in python these days.

* Asyncio doesn't add multi-core scaling to python. It's not a replacement for threads and doesn't lift the GIL-imposed scaling limitations. If these things are what you're after from asyncio you'll be disappointed, but they're not what it's trying to add and not adding them doesn't make it a failure.

* "Coloured functions" is a nonsense argument and that article made the whole world slightly more dumb.

* The GIL is part of the reason for python's success. I hope nogil either somehow manages to succeed without compromising the benefits the GIL has brought (I'll be amazed if that happens) or fails entirely. Languages are tools and every tool in your toolbox doesn't have to eventually turn into a drill. If your use case requires in-process parallelisation of interpreted CPU-bound workloads across multiple cores, python is just the wrong thing to use.

* It is indeed extremely annoying that we don't have async file access yet. I hope we get it soon.

lstodd 9/2/2025||
idk stackless dates back to 2005 at least, most likely earlier.

greenlet which is sort of minimal stackless .. before 2008

pycoev which is on one hand greenlets without memmove()s, on the other hand sort of io-scheduled m:n threading I wrote myself in 2009.

so, at least idk, 20 years?

It was first needed. Then 10 years passed, people got around to pushing it through the process aaand by the time it was done it was already not needed. so it all stalled. Same with Rust.

Nowadays server-side async is handled very differently. And client-side is dominated by that abomination called JS.

fulafel 9/2/2025||
Also back then multicore wasn't as prevalent, it made sense to multiplex a zillion things onto one CPU process. Whereas now servers have hundreds of cores / SMT vCPUs [1] and running a lot of processes makes much more sense.

[1] https://www.tomshardware.com/pc-components/cpus/amd-announce...

toolslive 9/2/2025||
I never understood why stackless wasn't more popular. It was rather nice, clean and performant (well, it's still python but it provide(d) proper concurrency)
lstodd 9/2/2025||
It was memmove() on each task switch. So you could forget about d-cache. And that killed performance on anything but benchmarks.
ack_complete 9/2/2025||
Also caused subtle bugs. I once had to debug a crash in C++ code that turned out to be due to Stackless Python corrupting stack state on Windows. OutputDebugString() would intermittently crash because Stackless had temporarily copied out part of the stack and corrupted the thread's structured exception handling chain. This wasn't obvious because this occurred in a very deep call stack with Stackless much higher up, and it only made sense if you knew that OutputDebugString() is implemented internally by throwing a continuable exception.

The more significant problem was that Stackless was a separate distribution. Every time CPython updated, there would be a delay until Stackless updated, and tooling like Python IDEs varied in whether they supported Stackless.

lstodd 9/2/2025||
We never ran stackless/greenlet under windows. And pycoev was setcontext(3)-based, so no windows either.

But I can imagine what that code did there...

nromiun 9/2/2025||
It was supposed to bring massive concurrency to Python. But as with any async implantation in any language it is too easy to deadlock the entire system. Did you forgot to sprinkle enough `await`? Your code is blocked somewhere, good luck hunting for it.

In contrast preemptive green threads are too easy. Be it IO or CPU load all threads will get their slice of CPU time. Nothing is blocked so you can debug your logic errors instead of deadlocks everywhere.

Async works in JS so well because the entire language is designed for it, instead of async being just bolted on. You can't even run plain `sleep` to block, you need setTimeout.

DanielHB 9/2/2025||
It is even funnier because JS only got proper async after, what? 25 years or so of existence. The main reason JS went all in with async is because it only ever had a single event loop and that naturally fits with the async model.

I still remember the days when all the libs started adopting async and how so many of them (to this day) support both passing callbacks or returning promises. Async just so naturally fixed the callback hell of 2010s JS that it just became standard even though it is not even heavily used in the browser APIs.

KingOfCoders 9/3/2025||
What I find funny is Java started with green threads, then moved away to system threads, then back again.
nromiun 9/3/2025||
Maybe massive concurrency was not that big of a feature back then. But these days everyone wants to support a million connections at a time. Green threads and async tasks can do that without breaking a sweat, unlike OS threads. Also, Java virtual threads are still cooperative. Maybe they will move to preemption in time like Go did.

Some time ago I tried to run just 10k OS threads on a small PC and it just crashed. So clearly OS threads have not improved much.

jpgvm 9/2/2025||
Because they chose the wrong API (well more correctly created a new, worse one).

In order to appease the various flavours they mixed and matched stuff from Tornado, gevent, etc.

They should have stuck with the most seamless of those (gevent) and instead of having it monkey-patch the runtime go the Java VirtualThread route and natively yield in all the I/O APIs.

This would have given a Go-esque ease of use and likely would have been immensely more popular.

wink 9/3/2025||
I think the 2/3 split had more impact than the author thinks.

Many people in my bubble (around 2013-2017) just never went with python 3, but chose other languages.

The company I was working for started important applications in python 2 as late as 2014 because the libraries we needed weren't ported yet. We never went python 3 later, but went to go instead, so we completely missed any python async thing.

breatheoften 9/3/2025|
The problem with python's async is asyncio ...

Structured concurrency libraries like anyio or trio are actually pretty nice -- "stacks" and stack traces are good things. Python multi exception concept is weird --- but also I think probably good ish.

It is still a pita to orchestrate around the gil/how terrible python multiprocessing side effects are wherever cpu bound workloads actually exist ...

More comments...