←back to thread

320 points willm | 1 comments | | HN request time: 0.207s | source
Show context
rsyring ◴[] No.45107080[source]
Not too long ago, I read a comment on HN that suggested, due to Python's support for free-threading, async in Python will no longer be needed and will lose out to free-threading due to it's use of "colored" functions. Which seems to align with where this author ends up:

> Because parallelism in Python using threads has always been so limited, the APIs in the standard library are quite rudimentary. I think there is an opportunity to have a task-parallelism API in the standard library once free-threading is stabilized.

> I think in 3.14 the sub-interpreter executor and free-threading features make more parallel and concurrency use cases practical and useful. For those, we don’t need async APIs and it alleviates much of the issues I highlighted in this post.

Armin recently put up a post that goes into those issue in more depth: https://lucumr.pocoo.org/2025/7/26/virtual-threads/

Which lead me to a pre-PEP discussion regarding the possibility of Virtual Threads in Python, which was probably way more than I needed to know but found interesting: https://discuss.python.org/t/add-virtual-threads-to-python/9...

replies(3): >>45107511 #>>45108190 #>>45109395 #
int_19h ◴[] No.45109395[source]
C# has had free threading all along, yet still saw the need for async as a separate facility.

The same goes for C++, which now has co_await.

replies(1): >>45111926 #
1. nine_k ◴[] No.45111926[source]
Threads are more expensive and slow to create. Submitting a task to a thread pool and waiting for a result, or a bunch of results, to show up, is much more ergonomic. So `async` automatically submits a task, and `await` awaits until it completes. Ideally `await` just discovers that a task (promise) has completed at that point, while the main thread was doing other things.

Once you have this in place, you can notice that you can "submit the task to the same thread", and just switch between tasks at every `await` point; you get coroutines. This is how generators work: `yield` is the `await` point.

If all the task is doing is waiting for I/O, and your runtime is smart enough to yield to another coroutine while the I/O is underway, you can do something useful, or at least issue another I/O task, not waiting for the first one to complete. This allows typical server code that does a lot of different I/O requests to run faster.

Older things like `gevent` just automatically added yield / await points at certain I/O calls, with an event loop running implicitly.