asyncio / async / await
asyncio is Python's standard asynchronous I/O framework. You define asynchronous functions (coroutines) with async def and use await to wait for another coroutine to complete. It runs multiple I/O-bound tasks concurrently in a single thread without using threads, making it especially effective for applications that handle many HTTP requests or file I/O operations.
Syntax
import asyncio
# Define an async function (coroutine)
async def my_coroutine():
await asyncio.sleep(1) # Wait asynchronously
return result
# Run a coroutine
asyncio.run(my_coroutine())
# Run multiple coroutines concurrently
results = await asyncio.gather(coro1(), coro2(), coro3())
Functions and Classes
| Function / Class | Description |
|---|---|
| async def func() | Defines an asynchronous function (coroutine function). |
| await expr | Waits for a coroutine, task, or Future to complete. Can only be used inside async def. |
| asyncio.run(coro) | Starts an event loop and runs the given coroutine. Requires Python 3.7+. |
| asyncio.gather(*coros) | Runs multiple coroutines concurrently and returns a list of their results. |
| asyncio.sleep(seconds) | Waits asynchronously for the specified number of seconds without blocking other coroutines. |
| asyncio.create_task(coro) | Schedules a coroutine to run as a task immediately. |
| asyncio.wait_for(coro, timeout) | Runs a coroutine with a timeout limit. |
| asyncio.Queue() | A FIFO queue for use in asynchronous code. |
Sample Code
import asyncio
import time
# Basic async function
async def say_hello(name, delay):
await asyncio.sleep(delay) # Other coroutines can run during this wait
print(f"Hello, {name}!")
async def main():
# Sequential execution (takes 3 seconds total)
await say_hello('Alice', 1)
await say_hello('Bob', 2)
asyncio.run(main())
# gather: concurrent execution (takes 2 seconds — the longest one)
async def main_parallel():
start = time.time()
await asyncio.gather(
say_hello('Alice', 1),
say_hello('Bob', 2),
say_hello('Carol', 1.5),
)
print(f"Total time: {time.time() - start:.1f}s") # About 2.0s
asyncio.run(main_parallel())
# create_task: schedule tasks to start immediately
async def fetch_data(url, delay):
await asyncio.sleep(delay)
return f"Data from {url}"
async def main_tasks():
# Register as tasks (they start right away)
task1 = asyncio.create_task(fetch_data('https://api1.example.com', 1))
task2 = asyncio.create_task(fetch_data('https://api2.example.com', 2))
result1 = await task1
result2 = await task2
print(result1)
print(result2)
asyncio.run(main_tasks())
# asyncio.Queue: producer-consumer pattern
async def producer(q, items):
for item in items:
await q.put(item)
await asyncio.sleep(0.5)
await q.put(None) # Sentinel value to signal completion
async def consumer(q):
while True:
item = await q.get()
if item is None:
break
print(f"Processing: {item}")
q.task_done()
async def main_queue():
q = asyncio.Queue()
await asyncio.gather(
producer(q, [1, 2, 3, 4, 5]),
consumer(q),
)
asyncio.run(main_queue())
Notes
asyncio uses a single-threaded event loop that switches between multiple coroutines to run them concurrently. When execution reaches an await, the event loop hands control to another coroutine, allowing I/O wait time to be used efficiently.
asyncio.gather() runs all coroutines concurrently and returns their results as a list. If any coroutine raises an exception, that exception is propagated. To suppress exceptions instead, pass return_exceptions=True.
asyncio is powerful for I/O-bound tasks, but it does not help with CPU-bound work — heavy computation blocks the event loop. To combine asyncio with CPU-bound processing, use asyncio.to_thread() (Python 3.9+) to delegate work to a thread. asyncio is also commonly paired with async-capable HTTP client libraries such as httpx or aiohttp.
If you find any errors or copyright issues, please contact us.