Skip to main content
The asyncio module provides infrastructure for writing single-threaded concurrent code using coroutines, event loops, and async/await syntax.

Module Import

import asyncio

Basic Async/Await

Coroutines

import asyncio

# Define async function
async def say_hello():
    print("Hello")
    await asyncio.sleep(1)
    print("World")

# Run coroutine
asyncio.run(say_hello())

Running Async Code

import asyncio

async def main():
    print("Started")
    await asyncio.sleep(1)
    print("Finished")

# Run async function
asyncio.run(main())

Concurrent Execution

gather() - Run Multiple Coroutines

import asyncio

async def fetch_data(id):
    await asyncio.sleep(1)
    return f"Data {id}"

async def main():
    # Run concurrently
    results = await asyncio.gather(
        fetch_data(1),
        fetch_data(2),
        fetch_data(3)
    )
    print(results)  # ['Data 1', 'Data 2', 'Data 3']

asyncio.run(main())

create_task() - Create Tasks

import asyncio

async def background_task():
    await asyncio.sleep(2)
    print("Background task complete")

async def main():
    # Create task (starts running)
    task = asyncio.create_task(background_task())
    
    # Do other work
    await asyncio.sleep(1)
    print("Main work done")
    
    # Wait for task
    await task

asyncio.run(main())

Timeouts and Waiting

wait_for() - Timeout

import asyncio

async def slow_operation():
    await asyncio.sleep(5)
    return "Done"

async def main():
    try:
        result = await asyncio.wait_for(slow_operation(), timeout=2.0)
    except asyncio.TimeoutError:
        print("Operation timed out")

asyncio.run(main())

wait() - Wait for Multiple Tasks

import asyncio

async def task(n):
    await asyncio.sleep(n)
    return n

async def main():
    tasks = [task(i) for i in [1, 2, 3]]
    
    # Wait for all
    done, pending = await asyncio.wait(tasks)
    
    for task in done:
        print(task.result())

asyncio.run(main())

Async Iteration

Async Generators

import asyncio

async def count_async(n):
    for i in range(n):
        await asyncio.sleep(0.1)
        yield i

async def main():
    async for number in count_async(5):
        print(number)

asyncio.run(main())

Queues

import asyncio

async def producer(queue):
    for i in range(5):
        await asyncio.sleep(0.1)
        await queue.put(i)
        print(f"Produced {i}")

async def consumer(queue):
    while True:
        item = await queue.get()
        print(f"Consumed {item}")
        queue.task_done()

async def main():
    queue = asyncio.Queue()
    
    # Start producer and consumer
    producer_task = asyncio.create_task(producer(queue))
    consumer_task = asyncio.create_task(consumer(queue))
    
    await producer_task
    await queue.join()  # Wait for all items processed
    consumer_task.cancel()

asyncio.run(main())

Practical Examples

Concurrent HTTP Requests

import asyncio
import aiohttp

async def fetch_url(session, url):
    async with session.get(url) as response:
        return await response.text()

async def main():
    urls = [
        'https://api.example.com/1',
        'https://api.example.com/2',
        'https://api.example.com/3',
    ]
    
    async with aiohttp.ClientSession() as session:
        tasks = [fetch_url(session, url) for url in urls]
        results = await asyncio.gather(*tasks)
        return results

asyncio.run(main())

Periodic Tasks

import asyncio

async def periodic_task(interval):
    while True:
        print(f"Running task every {interval}s")
        await asyncio.sleep(interval)

async def main():
    task = asyncio.create_task(periodic_task(2))
    await asyncio.sleep(10)  # Run for 10 seconds
    task.cancel()

asyncio.run(main())
Use asyncio for I/O-bound concurrent operations like network requests and file I/O.
Don’t use asyncio for CPU-bound tasks - use multiprocessing instead.

threading

Thread-based parallelism

multiprocessing

Process-based parallelism

Build docs developers (and LLMs) love