Understand the contract
async def defines a coroutine function. Calling it creates a coroutine object; it does not immediately run the body to completion. Awaiting it or scheduling it with an event loop is what drives execution. await obtains an awaitable's result and allows suspension while that operation is incomplete.
Async code supports cooperative concurrency, especially for waiting on I/O. It is not automatic CPU parallelism. A long calculation or blocking time.sleep call inside a coroutine can prevent other tasks on that loop from progressing.
Follow the runtime behavior
asyncio.run starts and manages a loop for a top-level script, executes the supplied coroutine, and closes its loop afterward. Each example is a complete Python 3.11+ script and uses sleep(0) only as a deterministic opportunity to yield control.
asyncio.run cannot be nested in an already running event loop, including many notebook or browser environments. There, use the host's supported top-level await main() instead of the final asyncio.run(main()) line. Do not nest another loop runner to work around the restriction.
Apply it and practise
Use await for operations with asynchronous APIs. Ordinary files and CPU work do not become nonblocking just because their surrounding function is async. Keep a single clear top-level runner in a normal script.
Exercise: define async double(value), await it for 3 and 5 inside main, and print the results in order. Explain why those two direct awaits are sequential, then compare with task scheduling in the related topic.
Syntax
async def main():
await asyncio.sleep(0)
asyncio.run(main())Examples
Await a coroutine result
Use this structure when a higher-level coroutine needs a result before continuing.
import asyncio
async def answer():
await asyncio.sleep(0)
return 42
async def main():
value = await answer()
print(value)
asyncio.run(main())- main awaits answer and receives its return value. sleep(0) cooperatively yields; no real elapsed-time measurement or external service is required.
- Use this structure when a higher-level coroutine needs a result before continuing.
- Run as a script. In a running notebook or browser loop, replace asyncio.run(main()) with supported top-level await main().
- Expected output: 42
Trace sequential awaits
Use sequential awaits when later operations depend on earlier completion.
import asyncio
async def step(name):
print(f"start {name}")
await asyncio.sleep(0)
print(f"end {name}")
async def main():
await step("A")
await step("B")
asyncio.run(main())- The first await must finish before main reaches the second statement. Yielding within A does not schedule B, because B has not yet been called.
- Use sequential awaits when later operations depend on earlier completion.
- Async syntax alone does not make these steps concurrent. asyncio.run also cannot be nested inside an already running host loop.
- Expected output: start A end A start B end B
Catch an asynchronous failure
Handle expected I/O or decoding failures at the coroutine layer that can recover.
import asyncio
async def load():
await asyncio.sleep(0)
raise ValueError("invalid record")
async def main():
try:
await load()
except ValueError as error:
print(error)
print("continued")
asyncio.run(main())- The exception raised inside load propagates through await to main's ordinary try/except. Handling it permits the next print to execute.
- Handle expected I/O or decoding failures at the coroutine layer that can recover.
- This is a standalone script; a running notebook/browser loop requires the host's await entry point rather than nested asyncio.run.
- Expected output: invalid record continued
Best practices
- asyncio.run cannot be nested in an already running event loop, including many notebook or browser environments. There, use the host's supported top-level await main() instead of the final asyncio.run(main()) line. Do not nest another loop runner to work around the restriction.
- Use await for operations with asynchronous APIs. Ordinary files and CPU work do not become nonblocking just because their surrounding function is async. Keep a single clear top-level runner in a normal script.
Runtime & versions
Python interpreter. Feature availability depends on the language and runtime version used by your project; consult the official reference below.
Python language reference