← Home ← Codex ← DEBT
Browse by Category
+ added · updated 7d
← Back to glossary

Python async/await & asyncio

Python Python 3.5+ Intermediate
debt(d6/e5/b7/t7)
d6 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7), but ruff/pylint can catch unawaited coroutines and mypy flags some async type mismatches, so slightly better at d6. Blocking calls like time.sleep() inside async functions are typically only caught by review or production latency symptoms.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5). Swapping requests for aiohttp or replacing time.sleep with asyncio.sleep cascades — async colors functions, so callers must also become async, often touching multiple files.

b7 Burden Structural debt — long-term weight of choosing wrong

Closest to 'strong gravitational pull' (b7). Async is famously 'viral' — once a function is async, every caller up the stack must await or be async too, shaping the architecture of web and CLI code across the codebase.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7). The misconception explicitly states devs assume async means parallelism, but it's single-threaded cooperative concurrency — contradicts threading/multiprocessing models. Also calling a coroutine without await silently returns a coroutine object rather than executing, which is deeply counterintuitive.

About DEBT scoring →

Also Known As

Python asyncio async await Python coroutines Python

TL;DR

Python's native async framework — coroutines, event loop, and asyncio — for concurrent I/O without threads.

Explanation

Python's asyncio provides a single-threaded event loop similar to Node.js. async def functions are coroutines — they don't run until awaited or scheduled. await suspends the coroutine until the awaited coroutine/task finishes. asyncio.gather(*coros) runs coroutines concurrently. asyncio.run(main()) starts the event loop. For CPU-bound work, asyncio doesn't help — use multiprocessing or ThreadPoolExecutor (loop.run_in_executor). Key difference from threading: no GIL contention, but no true parallelism either — only concurrency for I/O. Libraries: httpx (async HTTP), asyncpg (async PostgreSQL), aiofiles (async file I/O), FastAPI (async web framework). Comparable to PHP's Fibers + Revolt, but asyncio is a mature standard library with rich ecosystem support.

Diagram

flowchart TD
    subgraph Sync_Python
        S1[Task A runs] --> S2[Task A waits for IO<br/>thread blocked]
        S2 --> S3[Task A resumes]
        S3 --> S4[Task B runs]
    end
    subgraph Async_Python
        A1[Task A starts] --> A2[await IO - suspended]
        A2 --> B1[Task B runs during A wait]
        B1 --> A3[Task A resumes]
        A3 & B1 -->|interleaved| FAST[Both complete faster]
    end
    subgraph asyncio
        LOOP2[Event loop<br/>asyncio.run]
        GATHER[asyncio.gather<br/>run concurrently]
        LOOP2 --> GATHER
    end
style A2 fill:#d29922,color:#fff
style FAST fill:#238636,color:#fff
style GATHER fill:#1f6feb,color:#fff

Common Misconception

Python async/await provides true parallelism. Python's asyncio is single-threaded cooperative concurrency — one coroutine runs at a time, yielding control at await points. For CPU-bound parallelism, use multiprocessing; for I/O-bound concurrency, asyncio is ideal.

Why It Matters

Python's asyncio enables concurrent I/O-bound operations in a single thread — async/await syntax makes concurrent HTTP calls and database queries readable without threads or callbacks.

Common Mistakes

  • Using blocking I/O inside async functions — blocks the entire event loop.
  • Not awaiting coroutines — calling an async function without await returns a coroutine object, not the result.
  • Using asyncio.run() inside an already-running event loop — raises RuntimeError.
  • CPU-bound work in async functions — use ProcessPoolExecutor, not asyncio, for CPU-heavy tasks.

Code Examples

✗ Vulnerable
# Blocking call inside async — freezes event loop:
async def fetch_data():
    time.sleep(2)  # Blocks! Use: await asyncio.sleep(2)
    data = requests.get(url)  # Blocks! Use: await aiohttp session
    return data
✓ Fixed
import asyncio
import aiohttp

# Async function — returns a coroutine
async def fetch_user(session: aiohttp.ClientSession, user_id: int) -> dict:
    async with session.get(f'https://api.example.com/users/{user_id}') as resp:
        return await resp.json()

# Fetch multiple users concurrently
async def fetch_all_users(user_ids: list[int]) -> list[dict]:
    async with aiohttp.ClientSession() as session:
        tasks = [fetch_user(session, uid) for uid in user_ids]
        return await asyncio.gather(*tasks)  # run concurrently

# Run:
users = asyncio.run(fetch_all_users([1, 2, 3, 4, 5]))

# async with — async context manager
# async for  — async iteration (e.g. streaming responses)
async def stream_lines(url: str):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            async for line in resp.content:
                yield line.decode('utf-8').strip()

Added 15 Mar 2026
Edited 22 Mar 2026
Views 61
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 2 pings S 0 pings M 0 pings T 2 pings W 0 pings T 0 pings F 1 ping S 0 pings S 0 pings M 1 ping T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 1 ping M 0 pings T 0 pings W
No pings yet today
No pings yesterday
Amazonbot 16 Perplexity 8 ChatGPT 6 Unknown AI 4 Google 4 Ahrefs 4 Scrapy 4 Meta AI 2 Claude 2 Bing 2 PetalBot 1
crawler 48 crawler_json 4 pre-tracking 1
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: High
⚡ Quick Fix
Use asyncio.gather() for concurrent I/O operations and async with for context managers in async code — synchronous blocking calls inside async functions block the entire event loop
📦 Applies To
python 3.5 web cli
🔗 Prerequisites
🔍 Detection Hints
time.sleep() or requests.get() in async function blocking event loop; missing await before coroutine call
Auto-detectable: ✓ Yes pylint ruff mypy asyncio-mode-pytest
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Medium ✗ Manual fix Fix: High Context: Function Tests: Update


✓ schema.org compliant