Nope. I really need to as it’s such an active area of development.
I’m not too knowledgeable about C++ but think it likely doesn’t work correctly if you use setjmp/longjmp. E.g. destructors don’t run, RAII breaks. I’m not pointing this out to discourage your work, just to explain why I suspect it is not feasible for CPython to use a technique like this. There are a lot of C++ extensions out there.
It’s a good issue to highlight. If you’re using free-form setjmp()/longjmp() then all of the problems you raise are problems. In coroutine.c, though, they are used as a tool to build managed coroutines. In particular, it is an error to destruct an incomplete coroutine (just like deleting an incomplete asycio.Task is an error). In other words, be it C or C++, your coroutine has to exit by the normal route (see note), and so all destructors (C++), or tidy-up code (C) will be executed, ie C++ extensions will work just fine.
(note) if you throw in C++, and don’t catch before the throw unwinds into Python, then things will go wrong. First, Python will be broken (C tidy-up will be missed), and that’s true of any cpython version. Also, at some point the C++ runtime will dive off the bottom of the coroutine’s stack, and anything below a coroutine’s stack bottom is not guaranteed - the function which manages starting & stopping coroutines which use a particular chunk of stack never returns. You can also chain coroutines - continue deeper into whatever you’re doing with a new stack chunk when your current coroutine’s stack chunk is nearly full. Don’t throw across those boundaries for the same reason - the C++ runtime won’t know to unwind to the different coroutine’s stack.
One thing that I keep circling around when I think about this is that -
when Python is built in free-threaded mode (and I very much support this to become default in the future - IMO this is one of the most valuable initiatives out there) there is no stdlib option for single process threads left. I assume this is correct, isn’t it?
Excuse me, but the thread is huge and maybe I’m asking something obvious or already asked.
I (unluckily) program in Java too using Spring Boot, and I must say virtual threads are a piece of cake. But AFAIK they are daemon threads. And AFAIK Python has some problems with them.
Side note: I’m not against the proposal. On the contrary, I’d like them.
Sorry, who is we?
As I dive deeper into Java’s Virtual Threads, I see that it’s a game changer due to the automatic ability to take advantage of multiple CPU cores.
If I am utilizing a 190-core machine - with Java Virtual threads, all 190 cores would be utilized. And this all happens automagically. I am hoping same can be achieved in Python.
If I am utilizing a 190-core machine and running thousands or millions of concurrent tasks in an asyncio event loop, all these tasks are utilizing only one of the cores. As an example - in my earlier post I referred to the mature acme library in python not supporting asyncio - even if this library got ported to asyncio, the asyncio event loop would still be utilizing only a single CPU core, which - unlike Virtual Threads - is not sufficient for massive scalability.
Asyncio is a form of cooperative multitasking. coroutines know that other coroutines executing in the same event loop will not execute concurrently. This provides well defined places, under the coroutines control, where concurrent changes may occur (during an await). If coroutines started executing in other threads one of the main benefits of cooperative multitasking is obviated…coroutines would have to guard against concurrent changes that could happen at any time, the benefits of well defined places where concurrency can occur are lost. For this reason, what you seem to be proposing (coroutines in the same event loop can execute concurrently in multiple threads) would be a breaking change and is unlikely to happen.
If a single event loop doesn’t meet your scalability requirements use multiple event loops, and keep in mind that coroutines executing in other event loops can make changes at any time rather than only when a coroutine awaits.
I don’t think this is true. Virtual threads all run in a single OS
thread, so they will only use a single core. The use case for them is
when you have a large number of I/O-bound tasks. If your tasks are
CPU-bound, you need OS threads.
I gather there’s a GIL-free version of Python in the works (actually for
real this time) that will address this. It will let you run 190 OS
threads, each of which can use acyncio to manage some subset of the
tasks. If virtual threads were available they could be used as an
alternative to asyncio within each OS thread, but on their own they
wouldn’t help with utilising multiple cores.
Any of us here (unless the package maintainers happen by coincidence to be participating in this thread). A discussion thread here is the wrong place to raise an issue that you have with a package not supporting asyncio.
sorry for the side comment, but - the “GIL-free version of Python” is not only “in the works”: it has been officially released since Python 3.13, and labelled as not experimental anymore in Python 3.14, 7 months ago. PEP 779 – Criteria for supported status for free-threaded Python | peps.python.org - maybe it is just that free threading binaries are not ready to download from the official downloads page (and maybe they should be!), but they are easy to get around.
They are easily available on Windows - pymanager install 3.14t.
The installers on Mac and Linux both have checkboxes to install the free-threaded build. It’s buried in a submenu though.
For uv or pymanager you can refer to it as “3.14t” in contexts where you select Python versions.