plugins/languages/python/skills/async/SKILL.md
Python 异步编程与并发规范 (asyncio 3.13+)。涵盖 async/await、TaskGroup 结构化并发、httpx 异步 HTTP、aiofiles、超时与取消、free-threading (PEP 703)。在写异步函数、并发调度、I/O 优化、迁移同步代码、调试 async bug 时使用。也触发于"asyncio"、"async/await"、"并发"、"httpx"、"TaskGroup"。
npx skillsauth add lazygophers/ccplugin python-asyncInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Python 3.13+, asyncio 优先。3.14 的 free-threading (PEP 703) 解决 CPU 密集, asyncio 仍是 I/O 密集首选。
| 场景 | 选择 |
|------|------|
| I/O 密集 (HTTP, DB, 文件) | async/await |
| CPU 密集 (计算、加密、图像) | asyncio.to_thread 或 free-threading (3.14t) 多线程 |
| 真并行 CPU | 3.13 用 multiprocessing, 3.14 用 free-threading 多线程 |
| 单次脚本, 一两个 I/O | 同步代码 + httpx.Client 即可, 别强上 async |
整个调用链要么全 async 要么全 sync。混合调用 (asyncio.run 嵌套, loop.run_until_complete 在异步上下文里) 会死锁。
import asyncio
import httpx
async def fetch_user(client: httpx.AsyncClient, uid: int) -> dict:
resp = await client.get(f"/users/{uid}")
resp.raise_for_status()
return resp.json()
async def main() -> None:
async with httpx.AsyncClient(base_url="https://api.example.com") as client:
user = await fetch_user(client, 1)
print(user)
asyncio.run(main()) # 进程入口唯一一次
并发首选 TaskGroup, 不用 asyncio.gather (除非确实需要 return_exceptions=True):
async def fetch_all(uids: list[int]) -> list[dict]:
async with httpx.AsyncClient() as client:
async with asyncio.TaskGroup() as tg:
tasks = [tg.create_task(fetch_user(client, uid)) for uid in uids]
return [t.result() for t in tasks]
TaskGroup 优势:
ExceptionGroup, 用 except* 处理 (见 python-error)async with 前等所有任务完成, 防止任务泄漏gather 仅在需要"全部跑完, 错误单独收集"时用:
results = await asyncio.gather(*tasks, return_exceptions=True)
asyncio.timeout (3.11+) 替代 wait_for:
async with asyncio.timeout(5.0):
data = await slow_operation()
# TimeoutError 在退出时抛出
不要用 wait_for (老 API, 取消语义有坑)。
CancelledError 是控制流而非异常, 不要吞掉:
async def worker():
try:
await do_work()
except asyncio.CancelledError:
await cleanup()
raise # 必须 re-raise
except Exception:
log.error("worker_failed", exc_info=True)
raise
清理用 try/finally 或 async with, 不要依赖捕获 CancelledError。
不要再用 requests / urllib:
# 复用 client (连接池, 性能 10x+)
async with httpx.AsyncClient(
base_url="https://api.example.com",
timeout=httpx.Timeout(10.0, connect=5.0),
limits=httpx.Limits(max_connections=100),
) as client:
resp = await client.get("/users", params={"page": 1})
每次请求都 httpx.AsyncClient() 是反模式 (无连接复用)。把 client 放在 app 生命周期 (FastAPI lifespan) 或 fixture 里。
异步上下文里读写文件:
import aiofiles
async with aiofiles.open("data.json") as f:
content = await f.read()
但小文件直接 Path.read_text() (同步, 几 ms) 比开 aiofiles 还快, 别过度异步化。
CPU 密集任务不要写成 async def, 会阻塞事件循环:
# 同步 CPU 函数
def compute_hash(data: bytes) -> str:
return hashlib.sha256(data).hexdigest()
# 在 async 上下文里调
result = await asyncio.to_thread(compute_hash, big_data)
3.14 free-threading (python3.14t) 让多线程真并行, 多核 CPU 任务可用 concurrent.futures.ThreadPoolExecutor, 但生态 (C 扩展兼容) 还在补齐, 生产环境先评估。
sem = asyncio.Semaphore(10) # 同时最多 10 并发
async def bounded_fetch(client, url):
async with sem:
return await client.get(url)
async with asyncio.TaskGroup() as tg:
for url in urls:
tg.create_task(bounded_fetch(client, url))
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
from sqlalchemy import select
engine = create_async_engine("postgresql+asyncpg://...")
async def get_user(session: AsyncSession, uid: int) -> User | None:
stmt = select(User).where(User.id == uid)
result = await session.execute(stmt)
return result.scalar_one_or_none()
不要在 async 代码里用同步 psycopg2 / sqlite3。
asyncio.run(main(), debug=True) 启用 debug 模式, 检测慢回调和未 await 协程PYTHONASYNCIODEBUG=1 环境变量同效果loop.set_slow_callback_duration(0.05) 报警长回调requests / urllib3 / aiohttp (新代码统一 httpx)asyncio.get_event_loop() (用 asyncio.get_running_loop() 或不用)time.sleep() (用 await asyncio.sleep())asyncio.run(...) 多次嵌套 (整个程序只一次)RuntimeWarning: coroutine 'x' was never awaited)to_threadfor x in tasks: await x (串行, 失去并发, 用 TaskGroup)CancelledErrortools
UI/UX 与布局设计——做界面布局/结构/导航/组件/交互的设计决策。触发:做UI/UX/布局/排版/导航/组件/交互/栅格/响应式/图表选型/字体配对。按媒介路由 HTML/Web、原生 App(iOS/Android/桌面)、CLI、TUI。需后端动态系统不适用;配色/主题/色板走姊妹 skill design-color。
tools
主题与配色设计——做颜色搭配/调色板/主题/品牌色阶/暗模式的设计决策。触发:选配色/调色/主题/色板/品牌色/暗模式/对比度/色盲/UI风格。按媒介路由 HTML/Web(CSS变量)、原生App(平台token)、CLI(ANSI)、TUI(真彩/256/16降级)。保证可访问性(对比度/色盲安全)。需后端动态系统不适用;UI/UX 布局/组件/交互走姊妹 skill design-uiux。
tools
跨任意组件(plugin/skill/agent/command)的验证驱动优化循环纪律 skill。当用户要优化某个已有组件却无明确方向、或要防止改了反而更差(自评乐观偏差 / 多维同改归因失效 / 为凑分加废话膨胀)、或要把一套通用「评分→单变量改→改后验证严格更好才留否则回滚→触顶停」的纪律套到任意组件上时使用。管优化过程本身的纪律(validation gate / ratchet / 独立验证 / 触顶停),不评单组件深度(交 skill-dev),不查插件接线(交 plugin-dev)。仅手动 /optimize-any 触发。
data-ai
两层规则记忆 (基于 .skein/spec)。planning 时 recall 召回相关规则、task finish 后 sediment 沉淀学习 + prune 自动精简过期/重复/断链规则。core 常驻硬规 + recall 按需召回, 经判定门自动写盘 (不逐次问用户)。产出 .skein/spec 下 core/recall 规则文件 + index。另支持空仓 bootstrap 播种规则基线、记忆大面积失效 (大重构/换栈) 时 reconstruct 可逆归档后按项目类型分型重建、maintain 手动体检 (超预算/stale/断链/重复/废弃, --apply 自动修复)、auto-fix (Stop hook 写 .pending-fix 标记 → main 派 skein-specer bg 跑 maintain --apply 全自动修, 断链只报告)。