其他
用 asyncio 编写高并发非阻塞 Python…
在构建异步 Web API、并发 I/O、爬虫或实时应用时,指导 asyncio 的正确使用、并发编排与常见陷阱规避。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 48/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 85/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 52/100 ×0.15
适用场景
用 asyncio 编写高并发非阻塞 P通用
解决思路
- 先做同步/异步选型:大量并发网络或数据库调用用 asyncio;CPU 密集型用 multiprocessing 或线程池;I/O 与 CPU 混合时用 asyncio.to_thread() 把 CPU 工作卸载出去;简单脚本、连接数少时用同步(更简单易调试);高并发 Web API 用异步框架(FastAPI、aiohttp)。
- 遵循关键规则:在同一条调用路径上要么全同步、要么全异步,不要混用,否则会产生隐藏阻塞和复杂度。
- 理解核心概念:事件循环(单线程协作式多任务,调度协程、处理 I/O、管理回调与 future)、协程(async def 定义、可暂停恢复)、任务(在事件循环上并发调度的协程)、future(表示异步操作最终结果的底层对象)、异步上下文管理器(async with 做资源清理)、异步迭代器(async for 遍历异步数据源)。
- 用 asyncio.run(main()) 作为入口启动(Python 3.7+)。
- 基础模式:用 async def 定义协程,内部用 await 调用异步操作并返回结果。
- 并发执行:用 asyncio.gather(*tasks) 并发运行多个协程并收集结果,例如把 [fetch_user(uid) for uid in user_ids] 作为任务列表传入。
- 任务管理:用 asyncio.create_task() 创建后台任务,先继续做其他工作,再通过 await task 等待并获取结果。
- 错误处理:用 try/except 包裹可能失败的异步操作并返回 None 等兜底值;用 asyncio.gather(*tasks, return_exceptions=True) 收集异常,再按 isinstance(r, Exception) 区分成功与失败结果。
- 超时处理:用 asyncio.wait_for(coro, timeout=2.0) 包裹操作,并捕获 asyncio.TimeoutError 处理超时。
- 避免忘记 await:直接调用 async_function() 只会返回协程对象而不执行,必须 await async_function()。
- 避免阻塞事件循环:不要用 time.sleep(),改用 await asyncio.sleep()。
- 正确处理取消:在协程中捕获 asyncio.CancelledError,执行清理后重新 raise 以传播取消。
- 不要在同步函数里直接 await:同步函数中应使用 asyncio.run(async_function()) 来运行异步代码。
- 测试异步代码:使用 pytest-asyncio,通过 @pytest.mark.asyncio 标记异步测试函数;用 pytest.raises(asyncio.TimeoutError) 配合 asyncio.wait_for 测试超时。
- 需要更深入的高级模式时,阅读 references/details.md 中的 Advanced Patterns 等详细章节。
适用边界 · 注意事项
- CPU 密集型计算场景(应改用 multiprocessing 或线程池)
- 连接数很少的简单脚本(同步实现更简单、更易调试)
- 无法保证同一调用路径全同步或全异步、会混用两者的代码库