Python 并发与异步:threading、多进程与 asyncio 实战
10/23/2025
Python 并发与异步:threading、多进程与 asyncio 实战
当程序需要同时处理大量 I/O 或计算任务,并发就会显得重要。Python 存在 GIL(全局解释器锁),因此需要理解 I/O 与 CPU 的差异:
- I/O 密集:网络请求、磁盘读写,适合多线程或
asyncio。 - CPU 密集:图像处理、数值计算,适合多进程或 C 扩展。
一、线程(threading)适合 I/O
import threading
import time
results = []
def io_task(i: int):
time.sleep(0.2) # 模拟 I/O 等待
results.append(f"done-{i}")
threads = [threading.Thread(target=io_task, args=(i,)) for i in range(10)]
[t.start() for t in threads]
[t.join() for t in threads]
print(results)
优点:API 简单,生态成熟。缺点:共享状态易出错,需要锁与队列。
二、多进程(multiprocessing)适合 CPU
from multiprocessing import Pool
def heavy(x: int) -> int:
s = 0
for _ in range(1_000_00):
s += x * x
return s
with Pool(processes=4) as pool:
out = pool.map(heavy, range(8))
print(out)
优点:绕过 GIL,CPU 利用率高。缺点:进程间通信成本大,启动慢。
三、异步(asyncio)适合大量 I/O
asyncio 通过事件循环调度协程,让单线程并行等待多个 I/O。
import asyncio
async def fetch(i: int) -> str:
await asyncio.sleep(0.2)
return f"res-{i}"
async def main():
tasks = [fetch(i) for i in range(10)]
results = await asyncio.gather(*tasks)
print(results)
asyncio.run(main())
优点:资源占用低、吞吐高。缺点:调试困难、同步代码迁移成本。
四、选择策略与混合架构
- I/O 密集:优先
asyncio;简单场景可用threading。 - CPU 密集:优先
multiprocessing,或借助numba/C 扩展。 - 混合:网络层
asyncio,计算层子进程;用队列/消息总线解耦。
五、实战建议
- 控制并发度:避免过多任务导致资源耗尽(连接数、文件句柄)。
- 超时与重试:对外部服务设定超时、指数退避重试;记录错误原因。
- 背压与限流:队列长度与生产消费速率要匹配,避免积压。
- 可观测性:为协程/线程添加上下文日志,附带请求 ID。
结语
并发没有银弹。先判断任务类型(I/O vs CPU),再选择合适模型,并在可观测性与错误处理上做好工程化建设,才能让性能与稳定性真正提升。