multiprocessing处理网络请求反而更慢,因其启动开销大(fork/spawn复制内存、重建解释器)、进程间通信需序列化、内存占用高,而I/O任务本质是等待非计算,asyncio单线程事件循环更匹配该特性。

因为 multiprocessing 在 I/O 密集场景下是“杀鸡用牛刀”——开销大、调度重、内存炸,而 asyncio 用单线程事件循环精准匹配 I/O 等待的本质。
为什么 multiprocessing 处理网络请求反而更慢?
进程启动本身就有显著开销:fork 或 spawn 都要复制内存页、重建解释器状态;每个进程默认带完整 Python 解释器和导入的模块副本。100 个 HTTP 请求用 multiprocessing.Pool 启 100 个进程?光初始化就卡住,更别说进程间通信(如 Queue)带来的序列化/反序列化拖累。
- 典型表现:
OSError: [Errno 24] Too many open files或进程启动超时 - I/O 任务本质是“等”,不是“算”——CPU 大部分时间空闲,multiprocessing 却强行分配核、抢占调度权
- 每个进程至少占用几 MB 内存,1000 并发连接 ≈ 数百 MB 内存,而 asyncio 下同等规模通常
asyncio 如何用单线程撑起高并发 I/O?
它不靠“多副本”,靠“让出控制权”:当一个 await aiohttp.get(...) 发起请求后,当前协程立刻挂起,事件循环马上切换到另一个就绪的协程继续执行。所有等待都在内核态由 epoll(Linux)或 IOCP(Windows)统一监听,无须线程/进程切换。
- 关键点:
await必须作用于真正异步的底层调用(如aiohttp、aiomysql),不能包裹requests.get()这类阻塞调用 -
asyncio.run()启动单个事件循环,所有协程共享同一线程栈,无锁竞争、无上下文切换开销 - 标准库
asyncio+ 第三方aiofiles/asyncpg已覆盖绝大多数 I/O 场景
threading 和 asyncio 的实际分界在哪?
不是“能不能用”,而是“值不值得引入复杂度”。如果只是偶尔发几个请求、脚本简单、依赖库不支持异步(比如某些闭源 SDK 只提供同步接口),threading 搭配 concurrent.futures.ThreadPoolExecutor 更快上线——但要注意 time.sleep() 不释放 GIL,必须用 await asyncio.sleep() 替代。
立即学习“Python免费学习笔记(深入)”;
- 常见误用:
async def f(): requests.get(...)—— 这会阻塞整个事件循环,等同于没异步 - 混合使用风险:
loop.run_in_executor()调用阻塞函数虽可行,但频繁跨线程调度会抵消 asyncio 优势 - 调试陷阱:协程对象打印出来是
<coroutine object ... at></coroutine>,忘了await或asyncio.run()就静默不执行
真正容易被忽略的是“I/O 是否可异步化”这个前提——不是所有 I/O 都天然适配 asyncio。文件读写在 Linux 上可通过 aiostream 或 aiofiles 异步,但 Windows 下部分操作仍需线程池兜底;某些 C 扩展库(如旧版 psycopg2)不提供异步接口,硬上 asyncio 反而要绕路。选型前先确认依赖链是否全栈异步,比纠结语法更重要。


















