asyncio适合I/O密集、无强状态依赖且全栈异步支持的场景;不适合CPU密集、含阻塞C扩展或依赖同步库的情况,混用会阻塞事件循环。

asyncio 适合什么场景,又不适合什么
如果 I/O 密集、协程间无强状态依赖、且你能控制所有关键库是否支持异步(比如 aiohttp 而非 requests),asyncio 是首选。它在单线程内靠事件循环调度,开销小、并发高。
但一旦混入 CPU 密集操作(如图像处理、数值计算),或调用大量阻塞式 C 扩展(如某些 numpy 操作未显式释放 GIL)、或依赖的第三方库只有同步接口(如多数 psycopg2 旧版本),asyncio 就会卡住整个事件循环——这不是 bug,是设计使然。
- 别指望
asyncio.to_thread()能“拯救”所有同步调用;频繁跨线程切走会抵消异步收益 -
asyncio.run()每次都新建事件循环,短生命周期脚本没问题,长期服务要自己管理asyncio.get_event_loop() - 调试时看到
RuntimeWarning: coroutine 'xxx' was never awaited,基本是忘了await或误把协程当普通函数调了
多进程 vs 多线程:GIL 不是唯一决定因素
Python 的 GIL 确实让多线程无法真正并行执行 CPU 密集任务,但这不等于“线程没用”。对 I/O 密集型任务(如大量 HTTP 请求、文件读写),threading 开销低、启动快、共享内存方便,反而是更轻量的选择。
而 multiprocessing 虽能绕过 GIL,但进程创建/通信成本高,对象序列化(pickle)限制多,且 Windows 下默认启动方式是 spawn,导致模块级代码重复执行——常见错误是把 if __name__ == '__main__': 漏掉,直接报 AttributeError: Can't get attribute 'xxx' on 。
立即学习“Python免费学习笔记(深入)”;
1、对ASP内核代码进行DLL封装,从而大大提高了用户的访问速度和安全性;2、采用后台生成HTML网页的格式,使程序访问速度得到进一步的提升;3、用户可发展下级会员并在下级购买商品时获得差额利润;4、全新模板选择功能;5、后台增加磁盘绑定功能;6、后台增加库存查询功能;7、后台增加财务统计功能;8、后台面值类型批量设定;9、后台财务曲线报表显示;10、完善订单功能;11、对所有传输的字符串进行安全
- 用
concurrent.futures.ThreadPoolExecutor控制线程数比裸写threading.Thread更安全,避免资源耗尽 -
multiprocessing.Pool的map()默认不支持关键字参数;要用starmap()或封装成单参数元组 - 子进程无法继承父进程的 logging 配置,需显式重置 handler 和 level
何时该上 trio / curio,而不是死磕 asyncio
asyncio 的 API 设计偏底层,取消传播、超时嵌套、任务隔离等逻辑容易出错。如果你的项目需要强可靠性(比如金融类定时结算、设备长连接保活),trio 的结构化并发模型会更省心:每个 async with trio.open_nursery() 块天然保证子任务全部结束才退出,异常自动传播,无需手动 gather() + cancel()。
但代价是生态窄——trio 兼容的 HTTP 客户端只有 httpx(且得指定 backend="trio"),数据库驱动几乎为零。你不能一边用 trio 写主逻辑,一边拿 asyncpg(只支持 asyncio)去查库,否则会触发 RuntimeError: This event loop is already running。
-
curio更激进,连async/await都不用,全靠async def+await+ 显式sleep(),学习曲线陡,社区支持弱,仅建议实验性项目尝试 - 别试图用
anyio当万能胶水——它只是统一了 API 表面,底层仍是asyncio或trio,切换后仍要重测所有 I/O 组件
混合模型不是银弹,但有时真得这么干
现实系统常同时存在 CPU 密集(如视频转码)、I/O 密集(如上报日志)、和外部阻塞调用(如调用某老 C 库的 SDK)。纯一种模型撑不住,必须分层:主线程跑 asyncio 处理网络,CPU 工作扔给 multiprocessing.Process,阻塞 SDK 调用丢进 concurrent.futures.ThreadPoolExecutor 并设好 max_workers=1 防止线程爆炸。
难点不在启动,而在状态同步与错误透传。比如子进程崩溃,asyncio 主循环不会自动感知;线程池里抛了异常,若没用 future.result() 主动取,就会静默丢失。
- 用
asyncio.Queue在协程与子进程间传数据,别用multiprocessing.Queue——后者不 await 友好 - 所有跨模型边界的操作,务必加超时(
asyncio.wait_for()、future.result(timeout=...)),否则一个卡死就拖垮全局 -
logging本身是线程安全的,但多进程下需用QueueHandler+ 单独日志进程,否则日志错乱或丢失









