Python's asyncio module allows you to write concurrent code using coroutines and an event loop. But does it actually run code in parallel?
The Difference Between Concurrency and Parallelism
Concurrency and parallelism sound similar but have distinct meanings:
So asyncio enables concurrency, but not parallelism. The key is that it uses cooperative multitasking - each coroutine yields control back to the event loop willingly.
How asyncio Works
Here is what happens in asyncio:
- You define multiple coroutines and add them to the event loop queue.
- The event loop runs one coroutine at a time until it hits an
await statement. - That coroutine yields control back to the loop, which then runs the next coroutine.
So the coroutines execute concurrently by rapidly switching between each other, but they do not execute in parallel on multiple CPUs.
import asyncio
async def coroutine1():
print('coroutine 1 starts')
await asyncio.sleep(1)
print('coroutine 1 ends')
async def coroutine2():
print('coroutine 2 starts')
await asyncio.sleep(2)
print('coroutine 2 ends')
asyncio.run(coroutine1())
asyncio.run(coroutine2())
This outputs:
coroutine 1 starts
coroutine 1 ends
coroutine 2 starts
coroutine 2 ends
When to Use asyncio
asyncio shines for IO-bound tasks like network calls and disk reads/writes. Using asyncio here avoids wasting cycles waiting on IO blocking.
For CPU-bound parallel processing, consider multiprocessing instead. But asyncio enables cleaner concurrent code in single-threaded Python.
The key is understanding asyncio provides concurrency, not parallelism. It rapidly switches between coroutines on the same thread rather than running them in parallel.