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 2
MichaelRazum 9/2/2025|
You can’t just plug and play it. As soon as you introduce async you need to have the runtime loop and so on. Basically the whole architecture needs to be redesigned
DrillShopper 9/2/2025||
It's this - asyncio is a nightmare to add to and get working in a code base not specifically designed for it, and most people aren't going to bother with that. asyncio is not good enough at anything it does to make it worth it to me to design my entire program around it.
whilenot-dev 9/2/2025||
asyncio has been designed to be as "plug and play" as it gets. I'd discourage it, but one could create async loops wherever one would need them, one separate thread per loop, and adapt the code base in a more granular fashion. Blocking through the GIL will persist, though.

For any new app that is mostly IO constraint I'd still encourage the use of asyncio from the beginning.

MichaelRazum 9/4/2025|||
Sure agree, for bi directional websocket communication it is the way to go. It's just that you have to really think it thorough when using it. Like using asyncio.sleep instead of sleep for example and there are more little things that could easily hurt the performance and advantages of it.
odyssey7 9/2/2025|||
I remember back when the “Pythonic” philosophy was to make the language accessible.

It’s clear that Dr. Frankenstein has been at large and managed to get his hands on Python’s corpse.

kstrauser 9/3/2025||
I don’t think that’s fair. Yeah, there is a lot to learn and keep track of. At the same time, it’s an inherently complex problem. From one POV, and async Python program looks a lot like a cooperative multitasking operating system, but with functions instead of processes. It was a lot harder to write well-behaved programs on classic Mac OS than it was on a Commodore 64, but that Mac app was doing an awful lot more than the C64 program was. You couldn’t write them the same way and expect good results, but instead had to go about it a totally different way. It didn’t mean the Mac way was bad, just that it had a lot more inherent complexity.
rdtsc 9/2/2025||
I never liked async in Python. I feel like it's a bad design pattern, a lot of borrowed from Twisted at the time. I always liked gevent/eventlet based approach and will likely always stick to using that. At the time Go and Elixir/Erlang had green threads (lightweight procs / goroutines) and in general I think that makes for a cleaner code base.
foresto 9/2/2025||
A little history...

During development, asyncio was called tulip. A quick search turns up this talk by Guido:

https://www.youtube.com/watch?v=aurOB4qYuFM

I seem to recall that Guido was in touch with the author of Twisted at the time, so design ideas from that project may have helped shape asyncio.

https://twisted.org/

Before asyncio, Python had asyncore, a minimal event loop/callback module. I think it was was introduced in Python 1.5.2, and remained part of the standard library until 3.12.

https://docs.python.org/3.11/library/asyncore.html

https://docs.python.org/3.11/library/asynchat.html

blibble 9/2/2025|
asyncore actually worked well, unlike asyncio

so of course in their infinite wisdom, they removed it

dapperdrake 9/2/2025||
Python's async is very difficult to use and debug. It seems to get stuck randomly, read like race conditions. And Python cannot work around this nicely with their lambdas only permitting a single expression in their body.

Not worth the trouble. Shell pipelines are way easier to use. Or simply waiting —no pun intended— for the synchronous to finish.

mixmastamyk 9/2/2025|
> lambdas only permitting a single expression

Use a tuple, maybe walrus, and return the last item[-1].

dapperdrake 9/2/2025||
That idea sounds good.

How do I get variables for not redoing long-running computations that depend on one-another? So, what if the third tuple value depends on the second and the second in turn depends on the first?

mixmastamyk 9/2/2025|||
That’s what walrus is for:

    future = lambda age: (
        print('Your age is:', age),
        older := age + 5,
        print('Your age in the future:', older),
        older,
    )[-1]

    print(future(20))

    # out
    Your age is: 20
    Your age in the future: 25
    25
int_19h 9/2/2025|||
You can abuse list and sequence comprehensions for this. `for..in` is effectively a variable binding since you can target a freshly created list or a tuple if you need to bind a single value. So:

  [x
   for x in [some_complicated_expression]
   if x > 0
   for y in [x + 1]
   ...
  ][0]
That said, I wouldn't recommend this because of poor readability.
kurtis_reed 9/2/2025||
The premise of the article is wrong. Async in Python is popular. I'd expect most new web backends to use it.

The article says SQLalchemy added async support in 2023 but actually it was 2020.

kamikaz1k 9/2/2025||
async python is awful. to me it is a by default avoid. and when you can't avoid, use only where it provides outsized benefit.
TZubiri 9/2/2025|
Sometimes less is more. When a program becomes so big, one of the hardest challenges is not to keep on adding stuff.
TheCondor 9/2/2025||
I generally like Python. I'm not a hater but I don't treat it like a religion either.

Async Python is practically a new language. I think for most devs, it's a larger than than 2 to 3 was. One of the things that made python uptake easy was the vast number of libraries and bindings to C libraries. With async you need new versions of that stuff, you can definitely use synchronous libraries but then you get to debug why your stuff blocks.

Async Python is a different debugging experience for most python engineers. I support a small handful of async python services and think it would be an accellerator for our team to rewrite them on Go.

When you hire python engineers, most don't know async that well, if at all.

If you have a mix of synchronous and asynchronous code in your org, you can't easily intermix it. Well you can, but it won't behave as you usually desire it to, it's probably more desirable to treat them as different code bases.

Not to be too controversial, but depending upon your vintage and they was you've learned to write software I think you can come to python and think async is divine manna. I think there are many more devs that come to python from datascience or scripting or maybe as a first language and I think they have a harder time accepting the value and need of async. Like I said above, it's almost an entirely different language.

zbentley 9/3/2025||
I don't love Python's async API either, but I think a lot of its complained-about complexity arises from two things: making "when does the coroutine start running" a very explicit point in code (hence the Task/awaitable-function dichotomy), and how it chooses to handle async cancellation: via exceptions.

And Python's async cancellation model is pretty nice! You can reason about interruptions, timeouts, and the like pretty well. It's not all roses: things can ignore/defer cancellations, and the various wrappers people layer on make it hard to tell where, exactly, Tasks get cancelled--awaitable functions are simple here, at least. But even given that, Python's approach is a decent happy medium between Node's dangling coroutines and Rust's no-cleanup-ever disappearing ones (glib descriptor: "it's pre-emptive parallelism, but without the parallelism").

More than a little, I think, of the "nobody does it this way" weirdness and frustration in Python asyncio arises from that. That doesn't excuse the annoyances imposed by the resulting APIs, but it is good to know.

rich_sasha 9/3/2025|
Cancellations probably caused more bugs in my async code than anything else.

If any code in your coroutine, including library code, has a broad try/except, there's good chances that eventually the cancellation exception will be swallowed up and ignored.

Catch-all try/except of course isn't the pinnacle of good software engineering, but it happens a lot, in particular in server-tyoe applications. You may have some kind of handler loop that handles events periodically, and if one such handling fails, with an unknowabl exception, you want to log it and continue. So then you have to remember to explicitly reraise cancellation errors.

Maybe it's the least bad Pythonic option, but it's quite clunky for sure.

KingOfCoders 9/3/2025||
I did a lot of Scala Futures and liked the concept, more than 'async' everywhere, because it was easier to reason what happens and functions were just functions. Since some years I use Go where this is even easier.

But it took me some time to realize I can do the same idioms in Go as in Scala:

  // Scala
  f := Future(x)
  // Do something else until you need f
  ...
  for r <- f { ... }
can be written as

  c := channel 
  // Do something else until you need the result
  ...
  r<-c
My mind model was channel as a queue, but it can easily be used like channel as a future for one value.

And `select` for more complicated versions.

I miss the easy composition and delaying of futures though (f.map etc.)

tschellenbach 9/2/2025|
Yes, this!. Its a mess, some typing, some async. No standardization/ one way to do things. Literally goes against the original ZEN of python

"There should be one-- and preferably only one --obvious way to do it : Aim for a single, clear solution to a problem. "

aquariusDue 9/2/2025|
Cue the zen of python apologists explaining how we just don't get it and that with enough reframing it'll click.

Snide remark aside, I actually like the Zen of Python as programming language folklore but in 2025 AD it's kinda crazy to pretend that Python actually adheres to those tenets or whatever you wish to call them, and I'd go as far as to claim that it does a disservice to a language flexible enough for a lot of use cases. There's even someone on YouTube developing a VR game with Python.

int_19h 9/2/2025|||
It has never been literally true anyway, not even back when it was originally written.
More comments...