Python Async and Await
Write concurrent I/O-bound code with coroutines, the event loop, and asyncio
Overview
async/await lets you write concurrent code that cooperatively yields control while waiting on I/O, all on a single thread. An async def function is a coroutine; calling it returns a coroutine object that only runs when driven by an event loop. This model shines for high-latency I/O (network, disk, databases) where threads would mostly sit idle.
Syntax / Usage
You define coroutines with async def, pause them with await, and run them with asyncio.run. await can only appear inside a coroutine.
import asyncio
async def fetch(name: str, delay: float) -> str:
await asyncio.sleep(delay) # non-blocking pause
return f"{name} done"
async def main() -> None:
# Run coroutines concurrently and collect results in order
results = await asyncio.gather(
fetch("a", 1.0),
fetch("b", 0.5),
)
print(results)
asyncio.run(main())
await suspends the current coroutine until the awaited awaitable completes, freeing the loop to run others.
Examples
Bound concurrency with a semaphore so you never exceed N in-flight tasks:
import asyncio
async def worker(sem: asyncio.Semaphore, item: int) -> int:
async with sem:
await asyncio.sleep(0.1)
return item * item
async def main() -> None:
sem = asyncio.Semaphore(3)
tasks = [worker(sem, i) for i in range(10)]
print(await asyncio.gather(*tasks))
asyncio.run(main())
Enforce a timeout and handle cancellation cleanly:
import asyncio
async def slow() -> str:
await asyncio.sleep(5)
return "finished"
async def main() -> None:
try:
result = await asyncio.wait_for(slow(), timeout=1.0)
except asyncio.TimeoutError:
result = "timed out"
print(result)
asyncio.run(main())
Common Mistakes
- Calling a coroutine without
await, which creates but never runs it (and warns "coroutine was never awaited") - Using blocking calls like
time.sleepor synchronousrequestsinside a coroutine, which stalls the whole loop - Calling
asyncio.runmore than once or from inside a running loop - Awaiting tasks sequentially in a loop when
asyncio.gatherwould run them concurrently - Forgetting to await or cancel background tasks, leading to "Task was destroyed but it is pending" warnings
See Also
python-concurrency python-iterators-protocol python-generators