GeezerVisonThe World Wide Web, restored to 800 pixels of glory. |
| Home|About|Gaming cabinet|Archives|How it works|Starter sites |
GeezerVison is showing docs.python.org — asyncio and free-threaded Python asyncio and free-threaded Python¶asyncio uses an event loop as a scheduler to enable highly efficient concurrency by switching between tasks to allow non-blocking I/O operations. This results in better performance for I/O-bound use cases. It also allows off-loading CPU-bound work to a thread or process pool, but that is still limited by the global interpreter lock in CPython. However, in free-threaded Python, the GIL is disabled and Python can run true multi-threaded code. This means that asyncio can now take advantage of multiple CPU cores without the limitations imposed by the GIL. Since Python 3.14, asyncio has first-class support for free-threaded Python, and the implementation of asyncio is safe to use in a multi-threaded environment. A single event loop on one core can handle many connections concurrently, but the Python code that runs to handle each one still executes serially. Once requests involve a non-trivial amount of per-request computation, that handling becomes the bottleneck, and a single core can no longer keep up. Combining asyncio with threads is most useful here: by running an event loop per thread, the handling of different requests can run in parallel across multiple CPU cores. It is also useful when you need to run blocking or CPU-bound code from an asyncio application. See also Scaling asyncio on Free-Threaded Python, a blog post by Kumar Aditya which explains the internal changes that make asyncio safe and efficient under free-threaded Python, together with benchmarks of the resulting improvements. Thread safety considerations¶While asyncio is designed to be thread-safe in a free-threaded Python environment, there are still some considerations to keep in mind when using asyncio with threads:
Using asyncio with threads¶asyncio supports running one event loop per thread, which allows you to take advantage of multiple CPU cores in a free-threaded Python environment. Each thread can run its own event loop, and tasks can be scheduled on those loops independently. Here’s an example of how to use asyncio with threads: import asyncio import threading async def worker(name: str) -> None: print(f"Worker {name} starting") await asyncio.sleep(1) print(f"Worker {name} done") def run_loop(name: str) -> None: asyncio.run(worker(name)) threads = [ threading.Thread(target=run_loop, args=(f"T{i}",)) for i in range(4) ] for t in threads: t.start() for t in threads: t.join() In this example, each thread creates its own event loop with
Producer/consumer across threads¶When a regular (non-asyncio) thread needs to hand work to an asyncio
event loop running in another thread, use a thread-safe primitive such
as import asyncio import queue import threading def producer(q: queue.Queue[int]) -> None: for i in range(5): print(f"Producing {i}") q.put(i) q.shutdown() async def consumer(q: queue.Queue[int]) -> None: while True: try: item = q.get_nowait() except queue.Empty: await asyncio.sleep(0.1) continue except queue.ShutDown: break print(f"Consumed {item}") await asyncio.sleep(item) q: queue.Queue[int] = queue.Queue() consumer_thread = threading.Thread( target=lambda: asyncio.run(consumer(q)) ) consumer_thread.start() producer(q) consumer_thread.join() The producer runs on the main thread while the consumer runs inside an
event loop on its own thread, yet they communicate safely through
© Copyright 2001 Python Software Foundation.
This page is licensed under the Python Software Foundation License Version 2. Examples, recipes, and other code in the documentation are additionally licensed under the Zero Clause BSD License. See History and License for more information. The Python Software Foundation is a non-profit corporation. Please donate. Last updated on Nov 12, 2026 (14:14 UTC). Found a bug? Created using Sphinx 9.1.1. |
| You are visitor 01402503 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |