python-async-patterns
npx machina-cli add skill aiskillstore/marketplace/python-async-patterns --openclawFiles (1)
SKILL.md
4.2 KB
Python Async Patterns
Asyncio patterns for concurrent Python programming.
Core Concepts
import asyncio
# Coroutine (must be awaited)
async def fetch(url: str) -> str:
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.text()
# Entry point
async def main():
result = await fetch("https://example.com")
return result
asyncio.run(main())
Pattern 1: Concurrent with gather
async def fetch_all(urls: list[str]) -> list[str]:
"""Fetch multiple URLs concurrently."""
async with aiohttp.ClientSession() as session:
tasks = [fetch_one(session, url) for url in urls]
return await asyncio.gather(*tasks, return_exceptions=True)
Pattern 2: Bounded Concurrency
async def fetch_with_limit(urls: list[str], limit: int = 10):
"""Limit concurrent requests."""
semaphore = asyncio.Semaphore(limit)
async def bounded_fetch(url):
async with semaphore:
return await fetch_one(url)
return await asyncio.gather(*[bounded_fetch(url) for url in urls])
Pattern 3: TaskGroup (Python 3.11+)
async def process_items(items):
"""Structured concurrency with automatic cleanup."""
async with asyncio.TaskGroup() as tg:
for item in items:
tg.create_task(process_one(item))
# All tasks complete here, or exception raised
Pattern 4: Timeout
async def with_timeout():
try:
async with asyncio.timeout(5.0): # Python 3.11+
result = await slow_operation()
except asyncio.TimeoutError:
result = None
return result
Critical Warnings
# WRONG - blocks event loop
async def bad():
time.sleep(5) # Never use time.sleep!
requests.get(url) # Blocking I/O!
# CORRECT
async def good():
await asyncio.sleep(5)
async with aiohttp.ClientSession() as s:
await s.get(url)
# WRONG - orphaned task
async def bad():
asyncio.create_task(work()) # May be garbage collected!
# CORRECT - keep reference
async def good():
task = asyncio.create_task(work())
await task
Quick Reference
| Pattern | Use Case |
|---|---|
gather(*tasks) | Multiple independent operations |
Semaphore(n) | Rate limiting, resource constraints |
TaskGroup() | Structured concurrency (3.11+) |
Queue() | Producer-consumer |
timeout(s) | Timeout wrapper (3.11+) |
Lock() | Shared mutable state |
Async Context Manager
from contextlib import asynccontextmanager
@asynccontextmanager
async def managed_connection():
conn = await create_connection()
try:
yield conn
finally:
await conn.close()
Additional Resources
For detailed patterns, load:
./references/concurrency-patterns.md- Queue, Lock, producer-consumer./references/aiohttp-patterns.md- HTTP client/server patterns./references/mixing-sync-async.md- run_in_executor, thread pools./references/debugging-async.md- Debug mode, profiling, finding issues./references/production-patterns.md- Graceful shutdown, health checks, signal handling./references/error-handling.md- Retry with backoff, circuit breakers, partial failures./references/performance.md- uvloop, connection pooling, buffer sizing
Scripts
./scripts/find-blocking-calls.sh- Scan code for blocking calls in async functions
Assets
./assets/async-project-template.py- Production-ready async app skeleton
See Also
Prerequisites:
python-typing-patterns- Type hints for async functions
Related Skills:
python-fastapi-patterns- Async web APIspython-observability-patterns- Async logging and tracingpython-database-patterns- Async database access
Source
git clone https://github.com/aiskillstore/marketplace/blob/main/skills/0xdarkmatter/python-async-patterns/SKILL.mdView on GitHub Overview
Learn asyncio-based patterns to run I/O-bound tasks in parallel while staying scalable and responsive. This skill covers gather-based concurrency, bounded concurrency with semaphores, TaskGroup for structured concurrency (3.11+), and timeouts, with guidance on avoiding blocking calls.
How This Skill Works
Patterns rely on Python's asyncio primitives: gather collects results, Semaphore limits concurrent work, TaskGroup provides structured concurrency and automatic cleanup, and asyncio.timeout enforces operation deadlines. The examples show how to wrap HTTP I/O with aiohttp and switch to non-blocking constructs.
When to Use It
- Fetch many URLs concurrently with aiohttp and asyncio.gather
- Limit concurrent requests to respect rate limits or scarce resources
- Run multiple independent tasks with automatic cleanup using TaskGroup
- Enforce maximum operation time with asyncio.timeout
- Replace blocking I/O and time.sleep with non-blocking async equivalents
Quick Start
- Step 1: Identify async tasks you can run concurrently
- Step 2: Implement with gather, Semaphore, or TaskGroup and run with asyncio.run(main())
- Step 3: Monitor results and catch exceptions to avoid unhandled errors
Best Practices
- Prefer TaskGroup for structured concurrency (3.11+) when possible
- Use asyncio.gather with return_exceptions=True for resilience
- Bound concurrency with asyncio.Semaphore to protect resources
- Wrap long waits with asyncio.timeout to avoid hanging
- Always use non-blocking I/O (aiohttp, aiofiles) and avoid time.sleep
Example Use Cases
- Concurrently fetch multiple pages from an API and handle partial failures
- Limit concurrent outbound requests to a rate-limited service
- Process a batch of items in parallel and clean up on completion
- Apply a timeout to slow external calls and fall back gracefully
- Replace blocking calls in legacy code with async equivalents
Frequently Asked Questions
Add this skill to your agents