Starting an Async Program
In Python 3.7 and above, you can use
to easily start your async program:
async def async_main(): await asyncio.sleep(1) print("Async") def main(): asyncio.run(async_main(), debug=True) if __name__ == "__main__": main()
To run an async program in other ways, you need to use the loop directly.
loop = asyncio.get_running_loop()
loop.run_until_completeif you have one function you need to run
loop.run_foreverif you never want to close the async loop
Running blocking synchronous functions after Python 3.9
You should avoid calling blocking I/O functions inside async code.
Instead, try to run the code using
This is available in Python 3.9 and above.
If your blocking functions share state or require some sort of synchronization, you will have to make sure that running them concurrently on multiple threads does not affect them.
Running all blocking code in a single thread
To avoid having to synchronize the threads started by
you can use
with a thread pool
with a single thread (
max_workers=1) so your blocking tasks are all run in the same thread.
async_executor = ThreadPoolExecutor( max_workers=1, thread_name_prefix="async_worker_thread" ) await asyncio.get_running_loop().run_in_executor( async_executor, blocking_function )
For debugging purposes, give the executor a reasonable name related to
the blocking functions you’ll run on it.
This should work in versions before Python 3.9.
loop.run_in_executor in a very similar way.
The problem is the blocking functions must wait for other blocking functions to finish. You could use multiple worker pools to group similar blocking tasks, e.g. one worker pool for redis connections.
Running blocking synchronous functions before Python 3.9
If you don’t have
asyncio.to_thread or you don’t want to run tasks in a single thread,
you can use
run_in_executor with the default executor:
await loop.run_in_executor(executor=None, func=blocking_func)
Starting a coroutine from a thread
If you are running code in a thread but need to start an asynchronous function,
you can use
to request that the async loop run the function.
You need access to the loop.
This is available in Python 3.5.1 and above.
Wait for result
You can use the optional
timeout parameter to specify how long to wait.
Optimization: Use a faster async loop
Use uvloop instead of the built-in loop for a potential performance increase.
Call uvloop.install() before calling asyncio.run() or manually creating an asyncio event loop.
What can run asynchronously?
- TCP, Unix sockets with the builtin asyncio streams
- External processes, with
- Queue putting and getting with an
- Other async synchronization,
asyncio.Event. Compare to thread synchronization APIs, such as
- Callback-based code bridged with async code using Futures
- Signal handling with
There is support for many types of network protocols, and other I/O bound tasks. Many projects have official libraries that support asyncio.
- aiohttp is a popular client and server HTTP library.
- Many HTTP APIs, such as FastAPI support running async code in response to an HTTP request.
- NATS with the official async library. It had significant changes with the v2 release, including Python 3.10 support.
- Kafka with aiokafka.
- ZeroMQ with the official library or aiozmq, which must use a custom async loop.
- Redis with either aioredis or asyncio-redis, which is not actively maintained.
- Memcache, redis, or in-memory caching with aiocache.
- Databases with asyncpg or databases.
- DNS with aiodns.
- Serial device access with aioserial
- Logging asynchronously with aiologger. Make sure to use the right repository.