Async Python: asyncio Crash Course

Part 14 of the Python for Everyone track. Last updated: September 2026.

asyncio lets one Python process juggle thousands of I/O-bound tasks — API calls, database queries, file reads — without threads. The mental model is small: async def, await, and an event loop that switches tasks while they wait.

Your first coroutine

import asyncio

async def greet():                 # async def makes a COROUTINE function
    await asyncio.sleep(1)         # await: pause here, let others run
    return "hello"

async def main():
    result = await greet()         # await runs the coroutine to completion
    print(result)

asyncio.run(main())                # entry point: runs the event loop

asyncio.run() is the standard entry point — it creates the event loop, runs your coroutine, and closes everything cleanly.

Concurrency with gather

import asyncio, time

async def fetch(site):
    await asyncio.sleep(1)         # pretend this is a network call
    return f"data from {site}"

async def main():
    start = time.perf_counter()
    # run all three CONCURRENTLY — total time ≈ 1s, not 3s
    results = await asyncio.gather(
        fetch("a.com"), fetch("b.com"), fetch("c.com")
    )
    print(results, f"took {time.perf_counter() - start:.1f}s")

asyncio.run(main())

asyncio.gather() is the workhorse: hand it coroutines, get all results back in order. Three 1-second waits finish in ~1 second total.

Timeouts and tasks

import asyncio

async def slow():
    await asyncio.sleep(10)

async def main():
    try:
        await asyncio.wait_for(slow(), timeout=2)   # cancel if too slow
    except asyncio.TimeoutError:
        print("timed out!")

    task = asyncio.create_task(slow())   # schedule in the background
    await asyncio.sleep(0.1)
    task.cancel()                        # stop it early
    print("cancelled:", task.cancelled())

asyncio.run(main())

When NOT to use asyncio

  • CPU-bound work (number crunching, image processing) — asyncio won't parallelize it; the GIL still applies. Use multiprocessing instead.
  • Simple scripts with one I/O call — plain synchronous code is clearer.
  • Libraries without async support can't be awaited — check for async APIs (httpx, aiosqlite, asyncpg).

Key takeaways

  • async def defines a coroutine; await pauses it while I/O happens.
  • asyncio.run(main()) is the entry point; asyncio.gather(...) runs things concurrently.
  • Use wait_for for timeouts and create_task for background work.
  • asyncio shines for I/O-bound workloads — not CPU-bound ones.

You've completed the Python for Everyone core track! All 14 posts are now live under the Python label. Next up on the roadmap: Python for Data Science.

Comments

Popular posts from this blog

Java Banking Finance Services and Insurance (BFSI) domain interview questions

JSP Servlet Interview Questions For Freshers Series 1

Java program to check even or odd number