Skip to content

Python asyncio Module: Detailed Overview and Examples

The asyncio module in Python provides support for asynchronous programming by using coroutines, tasks, and event loops. It allows you to write concurrent code using the async and await syntax, making it easier to handle tasks that involve I/O operations, networking, and other asynchronous activities.

Importing the asyncio Module

To use the functions and classes from the asyncio module, you need to import it:

import asyncio

Key Components

1. Event Loop

The event loop is the core component of asyncio that manages and executes asynchronous tasks.

Example

import asyncio

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

# Run the event loop
asyncio.run(hello_world())

2. Coroutines

Coroutines are functions defined with the async def syntax. They use await to yield control to the event loop.

Example

import asyncio

# Define a coroutine
async def greet(name):
    print(f"Hello, {name}!")
    await asyncio.sleep(1)
    print(f"Goodbye, {name}!")

# Run the coroutine
asyncio.run(greet("Alice"))

3. Tasks

Tasks are used to schedule coroutines to run concurrently. They are created using asyncio.create_task() or loop.create_task().

Example

import asyncio

async def task1():
    print("Task 1 start")
    await asyncio.sleep(2)
    print("Task 1 end")

async def task2():
    print("Task 2 start")
    await asyncio.sleep(1)
    print("Task 2 end")

# Run multiple tasks concurrently
async def main():
    await asyncio.gather(task1(), task2())

asyncio.run(main())

4. asyncio.gather()

asyncio.gather() is used to run multiple coroutines concurrently and wait for them to complete.

Example

import asyncio

async def fetch_data(x):
    print(f"Fetching data {x}")
    await asyncio.sleep(x)
    return f"Data {x}"

async def main():
    results = await asyncio.gather(fetch_data(2), fetch_data(1))
    print(results)

asyncio.run(main())

5. asyncio.sleep()

asyncio.sleep() is a coroutine that pauses execution for a given number of seconds.

Example

import asyncio

async def delay_print():
    print("Start")
    await asyncio.sleep(2)
    print("End")

asyncio.run(delay_print())

6. asyncio.Queue

asyncio.Queue provides a FIFO queue for coroutines, allowing safe concurrent access.

Example

import asyncio

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

async def consumer(queue):
    while True:
        item = await queue.get()
        if item is None:
            break
        print(f"Consumed {item}")
        await asyncio.sleep(2)

async def main():
    queue = asyncio.Queue()
    await asyncio.gather(producer(queue), consumer(queue))

asyncio.run(main())

7. Exception Handling

Handling exceptions in asynchronous code is similar to synchronous code but should be done using try and except within coroutines.

Example

import asyncio

async def error_task():
    try:
        await asyncio.sleep(1)
        raise ValueError("An error occurred")
    except ValueError as e:
        print(f"Caught exception: {e}")

asyncio.run(error_task())

8. asyncio.Event

asyncio.Event is a simple synchronization primitive that allows coroutines to wait for an event to be set.

Example

import asyncio

async def waiter(event):
    print("Waiting for event")
    await event.wait()
    print("Event received")

async def setter(event):
    print("Setting event")
    await asyncio.sleep(2)
    event.set()

async def main():
    event = asyncio.Event()
    await asyncio.gather(waiter(event), setter(event))

asyncio.run(main())

9. asyncio.Semaphore

asyncio.Semaphore is used to limit the number of coroutines accessing a resource concurrently.

Example

import asyncio

async def worker(semaphore, num):
    async with semaphore:
        print(f"Worker {num} is working")
        await asyncio.sleep(2)
        print(f"Worker {num} done")

async def main():
    semaphore = asyncio.Semaphore(2)  # Limit to 2 concurrent workers
    await asyncio.gather(
        worker(semaphore, 1),
        worker(semaphore, 2),
        worker(semaphore, 3)
    )

asyncio.run(main())

10. asyncio.Timeout

asyncio.Timeout allows you to specify a timeout for coroutines.

Example

import asyncio

async def long_task():
    await asyncio.sleep(5)

async def main():
    try:
        await asyncio.wait_for(long_task(), timeout=2)
    except asyncio.TimeoutError:
        print("Task timed out")

asyncio.run(main())

Conclusion

The asyncio module is a powerful tool for writing concurrent code in Python using asynchronous programming. It provides a range of components, including coroutines, tasks, and synchronization primitives, to manage and execute asynchronous operations. By understanding and leveraging these components, you can write efficient and scalable code for applications that involve I/O-bound tasks, networking, and other asynchronous activities.