Lab 05: Async / Await

Objective

Write asynchronous Python programs using asyncio: coroutines, tasks, gather, async for, async context managers, queues, and concurrent I/O patterns.

Time

35 minutes

Prerequisites

  • Lab 03 (Generators), Lab 04 (Concurrency)

Tools

  • Docker image: zchencow/innozverse-python:latest


Lab Instructions

Step 1: Coroutines & Event Loop

docker run --rm zchencow/innozverse-python:latest python3 -c "
import asyncio
import time

async def say_hello(name: str, delay: float) -> str:
    await asyncio.sleep(delay)  # non-blocking sleep
    message = f'Hello from {name}!'
    print(f'  {message}')
    return message

async def main():
    print('=== Sequential (await one at a time) ===')
    start = time.perf_counter()
    r1 = await say_hello('Alice', 0.03)
    r2 = await say_hello('Bob',   0.02)
    r3 = await say_hello('Carol', 0.04)
    print(f'Sequential: {time.perf_counter()-start:.3f}s')

    print()
    print('=== Concurrent (asyncio.gather) ===')
    start = time.perf_counter()
    results = await asyncio.gather(
        say_hello('Alice', 0.03),
        say_hello('Bob',   0.02),
        say_hello('Carol', 0.04),
    )
    print(f'Concurrent: {time.perf_counter()-start:.3f}s')
    print('Results:', results)

asyncio.run(main())
"

💡 asyncio.gather() runs coroutines concurrently on a single thread by interleaving them on the event loop. When one coroutine awaits (I/O, sleep), the event loop runs another. Unlike threads, there's no GIL issue and no data races — only one coroutine runs at a time, but they overlap on I/O waits.

📸 Verified Output:


Step 2: Tasks, Timeouts & Cancellation

📸 Verified Output:


Steps 3–8: Async Generators, Queues, Semaphore, Context Managers, HTTP simulation, Capstone

📸 Verified Output:


Summary

Concept
Syntax
Notes

Define coroutine

async def fn():

Must be awaited

Await

result = await coro()

Suspends until done

Run event loop

asyncio.run(main())

Python 3.7+

Concurrent

asyncio.gather(c1, c2)

Run coroutines in parallel

Task

asyncio.create_task(coro)

Schedule without blocking

Timeout

asyncio.wait_for(coro, timeout=N)

Raises TimeoutError

Async generator

async def gen(): yield ...

Use with async for

Async context

async with ctx_mgr:

Pairs with __aenter__/__aexit__

Further Reading

Last updated