Home/Learn/Python A–Z/asyncio — async/await and the Event Loop

asyncio — async/await and the Event Loop

Advanced
Concurrency

asyncio runs thousands of concurrent I/O operations on one thread: coroutines pause at await, the event loop switches to whoever is ready, and gather fans out work — as long as nothing blocks the loop.

Overview

asyncio is cooperative multitasking: an async def function is a coroutine that runs until it hits await, then hands control back to the event loop, which resumes some other coroutine whose I/O completed. One thread, no locks for most code, and scaling to tens of thousands of concurrent connections — this is the engine under FastAPI, aiohttp, and every modern Python web stack. The model has one iron rule: never call blocking functions (time.sleep, requests.get, heavy CPU loops) inside a coroutine, because they freeze the single thread and every other task with it. The fix is an async library (httpx, asyncpg) or asyncio.to_thread for the stubborn cases.

Coroutines, await, and gather

Calling an async function returns a coroutine object; nothing runs until it is awaited. asyncio.gather starts several at once and their waits overlap — three service calls finish in the time of the slowest one, not the sum.

gather overlaps the waits: slowest call decides total time
import asyncio
import time

async def call_service(name, delay):
    await asyncio.sleep(delay)       # yields to the event loop while "waiting"
    return f"{name}: ok ({delay}s)"

async def main():
    start = time.perf_counter()

    results = await asyncio.gather(
        call_service("orders", 1.0),
        call_service("payments", 1.5),
        call_service("inventory", 1.2),
    )
    for r in results:
        print(r)
    print(f"total: {time.perf_counter() - start:.1f}s")   # ~1.5s, not 3.7s

asyncio.run(main())      # the ONE entry point — creates and closes the loop

# create_task: start now, await later
async def dashboard():
    task = asyncio.create_task(call_service("analytics", 2.0))
    print("doing other work while analytics runs...")
    print(await task)

The Iron Rule — Never Block the Loop

One blocking call stalls every coroutine in the process. In a FastAPI service, one time.sleep(5) inside an async endpoint freezes all in-flight requests for 5 seconds. Use async-native libraries, or push blocking work to a thread with asyncio.to_thread.

Blocking vs yielding — and to_thread as the escape hatch
import asyncio
import time

async def bad():
    time.sleep(2)                # ✗ BLOCKS the whole event loop for 2s
    # every other task in the process is frozen meanwhile

async def good():
    await asyncio.sleep(2)       # ✓ loop keeps serving other tasks

def legacy_report():             # blocking library you cannot change
    time.sleep(2)
    return "report ready"

async def main():
    # to_thread: run blocking code in a worker thread, await the result
    result = await asyncio.to_thread(legacy_report)
    print(result)

    # timeout guard — production habit for every external await
    try:
        await asyncio.wait_for(asyncio.sleep(10), timeout=1.0)
    except TimeoutError:
        print("gave up after 1s")

asyncio.run(main())

# Ecosystem: requests → httpx.AsyncClient, psycopg2 → asyncpg,
# time.sleep → asyncio.sleep. FastAPI async def endpoints live on this loop.

Key Points to Remember

  • 1async def defines a coroutine; it runs only when awaited; asyncio.run() starts the loop
  • 2gather/create_task overlap I/O waits — total time ≈ the slowest task
  • 3Never block the loop: no time.sleep, no requests.get inside coroutines
  • 4asyncio.to_thread bridges blocking libraries; wait_for adds timeouts

Interview Questions

Sign in to ask Aria
1

What happens if you call time.sleep(5) inside an async FastAPI endpoint?

MediumCRED
2

Difference between await coro(), create_task(), and gather()?

MediumHotstar
3

asyncio is single-threaded — how does it handle 10,000 concurrent connections?

HardZerodha

Ask Aria about asyncio — async/await and the Event Loop

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…