关于 async-python-patterns
为 Python 开发者提供 asyncio 异步编程模式与实践指导的技能,适用于构建异步应用及处理 I/O 密集型并发任务。内容涵盖任务管理、错误与超时处理、流式处理、同步机制、测试和性能实践。
主要功能
- 01协程与并发任务模式
- 02任务取消、错误及超时处理
- 03异步迭代器与生产者消费者队列
- 04信号量和锁等同步机制
- 05连接池与事件循环性能实践
- 06异步代码测试指导
适用场景
- 01实现并发 API 或数据库调用
- 02构建异步爬虫与实时应用
- 03协调后台任务和队列处理
- 04测试及优化 I/O 密集型程序
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ nickcrew/ claude-cortex --skill async-python-patterns安装后在 Claude Code 中输入/async-python-patterns确认已加载。
详细介绍
异步 Python 模式
为使用 asyncio、并发编程模式和 async/await 构建高性能、非阻塞系统的异步 Python 应用提供专家指导。
何时使用此技能
- 构建异步 Web API(FastAPI、aiohttp、Sanic)
- 实现并发 I/O 操作(数据库、文件、网络)
- 创建可并发发送请求的网页抓取工具
- 开发实时应用(WebSocket 服务、聊天系统)
- 同时处理多个相互独立的任务
- 优化需要并行处理的 I/O 密集型工作负载
- 实现异步后台任务和任务队列
核心模式
1. 基本的 Async/Await
所有异步操作的基础:
import asyncio
async def fetch_data(url: str) -> dict:
"""Fetch data asynchronously."""
await asyncio.sleep(1) # Simulate I/O
return {"url": url, "data": "result"}
async def main():
result = await fetch_data("https://api.example.com")
print(result)
asyncio.run(main())
关键概念:
async def定义协程(可暂停的函数)await将控制权交还给事件循环asyncio.run()是入口点(Python 3.7+)- 单线程协作式多任务处理
2. 使用 gather() 并发执行
同时执行多个操作:
import asyncio
from typing import List
async def fetch_user(user_id: int) -> dict:
await asyncio.sleep(0.5)
return {"id": user_id, "name": f"User {user_id}"}
async def fetch_all_users(user_ids: List[int]) -> List[dict]:
"""Fetch multiple users concurrently."""
tasks = [fetch_user(uid) for uid in user_ids]
results = await asyncio.gather(*tasks)
return results
# Speed: Sequential = 5s, Concurrent = 0.5s for 10 users
适用场景:
- 可以并行运行的独立操作
- I/O 密集型任务(API 调用、数据库查询)
- 需要在继续执行前获取所有结果
- 使用
return_exceptions=True处理部分失败
3. 任务的创建与管理
独立运行的后台任务:
import asyncio
async def background_task(name: str, delay: int):
print(f"{name} started")
await asyncio.sleep(delay)
return f"Result from {name}"
async def main():
# Create tasks (starts execution immediately)
task1 = asyncio.create_task(background_task("Task 1", 2))
task2 = asyncio.create_task(background_task("Task 2", 1))
# Do other work while tasks run
print("Doing other work")
await asyncio.sleep(0.5)
# Wait for results when needed
result1, result2 = await task1, await task2
区别:
await coroutine()— 立即等待asyncio.create_task()— 启动后台执行- 可以使用
task.cancel()取消任务
4. 错误处理
针对并发操作的稳健错误处理:
import asyncio
from typing import List, Optional
async def safe_operation(item_id: int) -> Optional[dict]:
try:
await asyncio.sleep(0.1)
if item_id % 3 == 0:
raise ValueError(f"Item {item_id} failed")
return {"id": item_id, "status": "success"}
except ValueError as e:
print(f"Error: {e}")
return None
async def process_items(item_ids: List[int]):
# gather with return_exceptions=True continues on errors
results = await asyncio.gather(
*[safe_operation(iid) for iid in item_ids],
return_exceptions=True
)
successful = [r for r in results if r and not isinstance(r, Exception)]
failed = [r for r in results if isinstance(r, Exception)]
print(f"Success: {len(successful)}, Failed: {len(failed)}")
return successful
5. 超时处理
防止操作无限期挂起:
import asyncio
async def with_timeout():
try:
result = await asyncio.wait_for(
slow_operation(5),
timeout=2.0
)
print(result)
except asyncio.TimeoutError:
print("Operation timed out")
# Handle timeout (retry, fallback, etc.)
高级模式
6. 异步上下文管理器
使用异步操作妥善管理资源:
import asyncio
class AsyncDatabaseConnection:
"""Async database connection with automatic cleanup."""
def __init__(self, dsn: str):
self.dsn = dsn
self.connection = None
async def __aenter__(self):
print("Opening connection")
await asyncio.sleep(0.1) # Simulate connection
self.connection = {"dsn": self.dsn, "connected": True}
return self.connection
async def __aexit__(self, exc_type, exc_val, exc_tb):
print("Closing connection")
await asyncio.sleep(0.1) # Simulate cleanup
self.connection = None
async def query_database():
async with AsyncDatabaseConnection("postgresql://localhost") as conn:
# Connection automatically closed on exit
return await perform_query(conn)
适用场景:
- 数据库连接(asyncpg、motor)
- HTTP 会话(aiohttp.ClientSession)
- 文件 I/O(aiofiles)
- 锁和信号量
7. 异步迭代器和生成器
以异步方式流式传输数据:
import asyncio
from typing import AsyncIterator
async def fetch_pages(url: str, max_pages: int) -> AsyncIterator[dict]:
"""Fetch paginated data lazily."""
for page in range(1, max_pages + 1):
await asyncio.sleep(0.2) # API call
yield {
"page": page,
"url": f"{url}?page={page}",
"data": [f"item_{page}_{i}" for i in range(5)]
}
async def process_stream():
async for page_data in fetch_pages("https://api.example.com", 10):
# Process each page as it arrives (memory efficient)
print(f"Processing page {page_data['page']}")
优点:
- 处理大型数据集时内存效率高
- 无需等待所有数据到达即可开始处理
- 可自然地处理背压
8. 使用队列实现生产者-消费者模式
协调生产者与消费者之间的工作:
import asyncio
from asyncio import Queue
async def producer(queue: Queue, producer_id: int, num_items: int):
for i in range(num_items):
item = f"Item-{producer_id}-{i}"
await queue.put(item)
await asyncio.sleep(0.1)
await queue.put(None) # Signal completion
async def consumer(queue: Queue, consumer_id: int):
while True:
item = await queue.get()
if item is None:
queue.task_done()
break
print(f"Consumer {consumer_id} processing: {item}")
await asyncio.sleep(0.2)
queue.task_done()
async def run_pipeline():
queue = Queue(maxsize=10)
# 2 producers, 3 consumers
producers = [asyncio.create_task(producer(queue, i, 5)) for i in range(2)]
consumers = [asyncio.create_task(consumer(queue, i)) for i in range(3)]
await asyncio.gather(*producers)
await queue.join() # Wait for all items processed
for c in consumers:
c.cancel()
9. 使用信号量进行速率限制
控制并发操作:
import asyncio
from typing import List
async def api_call(url: str, semaphore: asyncio.Semaphore) -> dict:
async with semaphore: # Only N operations at once
print(f"Calling {url}")
await asyncio.sleep(0.5)
return {"url": url, "status": 200}
async def rate_limited_requests(urls: List[str], max_concurrent: int = 5):
semaphore = asyncio.Semaphore(max_concurrent)
tasks = [api_call(url, semaphore) for url in urls]
return await asyncio.gather(*tasks)
# Limits to 5 concurrent requests regardless of total URLs
适用场景:
- API 速率限制(遵守 API 配额)
- 数据库连接数限制
- 文件描述符数量限制
- 内存受限的操作
10. 使用异步锁保护共享状态
在异步上下文中执行线程安全的操作:
import asyncio
class AsyncCounter:
def __init__(self):
self.value = 0
self.lock = asyncio.Lock()
async def increment(self):
async with self.lock:
current = self.value
await asyncio.sleep(0.01) # Simulate work
self.value = current + 1
async def get_value(self) -> int:
async with self.lock:
return self.value
同步原语:
Lock:互斥Event:在任务之间发送信号Condition:等待条件满足Semaphore:限制并发访问
性能最佳实践
1. 使用连接池
复用连接以提高效率:
import aiohttp
async def with_connection_pool():
connector = aiohttp.TCPConnector(limit=100, limit_per_host=10)
async with aiohttp.ClientSession(connector=connector) as session:
tasks = [session.get(f"https://api.example.com/item/{i}")
for i in range(50)]
return await asyncio.gather(*tasks)
2. 避免阻塞事件循环
在执行器中运行 CPU 密集型任务:
import asyncio
import concurrent.futures
def blocking_operation(data):
"""CPU-intensive blocking operation."""
import time
time.sleep(1)
return data * 2
async def run_in_executor(data):
loop = asyncio.get_event_loop()
with concurrent.futures.ThreadPoolExecutor() as pool:
result = await loop.run_in_executor(pool, blocking_operation, data)
return result
应避免的常见阻塞操作:
time.sleep()— 使用asyncio.sleep()- 同步文件 I/O — 使用
aiofiles - 同步 HTTP — 使用
aiohttp或httpx - 大量计算 — 使用
loop.run_in_executor()
3. 批量处理操作
分块处理以控制内存用量:
async def batch_process(items: List[str], batch_size: int = 10):
for i in range(0, len(items), batch_size):
batch = items[i:i + batch_size]
results = await asyncio.gather(*[process_item(item) for item in batch])
print(f"Processed batch {i // batch_size + 1}")
常见问题
1. 忘记使用 await
# Wrong - returns coroutine, doesn't execute
result = async_function()
# Correct
result = await async_function()
2. 阻塞事件循环
# Wrong - blocks entire event loop
import time
async def bad():
time.sleep(1)
# Correct
async def good():
await asyncio.sleep(1)
3. 未处理取消操作
async def cancelable_task():
try:
while True:
await asyncio.sleep(1)
except asyncio.CancelledError:
# Cleanup resources
raise # Re-raise to propagate
4. 混用同步和异步代码
# Wrong
def sync_function():
result = await async_function() # SyntaxError
# Correct
def sync_function():
result = asyncio.run(async_function())
测试异步代码
使用 pytest-asyncio 进行测试:
import pytest
@pytest.mark.asyncio
async def test_async_function():
result = await fetch_data("https://api.example.com")
assert result is not None
@pytest.mark.asyncio
async def test_with_timeout():
with pytest.raises(asyncio.TimeoutError):
await asyncio.wait_for(slow_operation(5), timeout=1.0)
资源
- Python asyncio 文档:https://docs.python.org/3/library/asyncio.html
- aiohttp:异步 HTTP 客户端/服务端框架
- FastAPI:现代异步 Web 框架,支持自动生成 OpenAPI
- asyncpg:高性能异步 PostgreSQL 驱动
- motor:适用于 Python 的异步 MongoDB 驱动
- pytest-asyncio:异步代码测试框架
最佳实践摘要
- 使用
asyncio.run()作为入口点(Python 3.7+) - 始终使用
await执行协程 - 使用
gather()并发执行相互独立的任务 - 使用 try/except 和
return_exceptions=True实现适当的错误处理 - 使用超时机制,防止操作挂起
- 使用连接池提升性能并管理资源
- 避免在异步代码中执行阻塞操作(必要时使用执行器)
- 使用信号量进行速率限制和资源控制
- 使用 CancelledError 妥善处理任务取消
- 使用 pytest-asyncio 彻底测试异步代码
评论
支持 Markdown