ReviseAlgo Logo

Concurrency

asyncio Basics

async/await syntax and the asyncio framework — writing concurrent code using coroutines, tasks, and the event loop for I/O-bound operations.

Interview: Modern Python concurrency — frequently asked in backend and systems design interviews.

Last Updated: June 12, 2026 10 min read

asyncio is Python's standard library framework for writing concurrent code using the async/await syntax. It's designed for I/O-bound tasks — network requests, database queries, file I/O — where the program spends most time waiting. Unlike threading, asyncio uses cooperative multitasking: coroutines explicitly yield control, avoiding race conditions inherent in preemptive threading.

Core Concepts

  • Coroutine: A function defined with async def — can pause execution with await
  • Event Loop: The runtime that schedules and runs coroutines
  • Task: A scheduled coroutine — asyncio.create_task() runs coroutines concurrently
  • Future: A placeholder for a result that will be available later
  • asyncio.run() — the main entry point that creates an event loop and runs a coroutine

async/await Syntax

  • async def defines a coroutine function (not a regular function)
  • await pauses the current coroutine until the awaited operation completes
  • You can only use await inside an async def function
  • Calling an async function without await returns a coroutine object (doesn't execute it)

Running Concurrent Tasks

  • asyncio.gather(*coros) — run multiple coroutines concurrently, collect all results
  • asyncio.create_task(coro) — schedule a coroutine to run in the background
  • asyncio.wait(tasks) — wait for tasks with options (FIRST_COMPLETED, ALL_COMPLETED)
  • asyncio.as_completed(tasks) — iterate over results as they finish

When to Use asyncio

  • HTTP clients making many requests (aiohttp, httpx)
  • Database queries (asyncpg, aiosqlite)
  • WebSocket servers and chat applications
  • Web frameworks like FastAPI and Starlette
  • Any scenario with many concurrent I/O operations

Interview Insight

Explain that asyncio is single-threaded — concurrency comes from cooperative multitasking, not parallelism. It's ideal for I/O-bound workloads with many concurrent operations. Compare with threading (preemptive, GIL-limited) and multiprocessing (true parallelism for CPU-bound work).

Common Pitfall

Never call blocking functions (time.sleep, requests.get) inside async code — it blocks the entire event loop. Use async alternatives (asyncio.sleep, aiohttp) or run blocking code in an executor.

Use Cases

Web scraping — concurrent HTTP requests to multiple pages

API aggregation — calling multiple microservices simultaneously

Real-time applications — WebSocket servers, chat systems

Async frameworks — FastAPI, Starlette, aiohttp servers

Batch I/O operations — sending emails, writing to databases concurrently

Common Mistakes

Forgetting await — calling async function without await returns a coroutine, not a result

Using blocking calls (time.sleep, requests.get) inside async — blocks the event loop

Creating coroutines without scheduling — use create_task() or gather() to run concurrently

Not handling exceptions in gather — one failure cancels all tasks unless return_exceptions=True

Mixing sync and async code — use asyncio.to_thread() or run_in_executor() for blocking calls