Python 线程池与进程池如何选择?

11次阅读

CPU密集型任务用进程池,IO密集型用线程池;混合场景可组合使用,小任务宜同步执行,资源受限时需合理设置池大小。

Python 线程池与进程池如何选择?

选线程池还是进程池,关键看任务类型:CPU密集型用进程池,IO密集型用线程池。

看任务是否频繁等待外部资源

如果任务大量时间花在等待网络响应、文件读写、数据库查询等操作上,属于IO密集型。这类任务线程切换开销小,GIL影响不大,用ThreadPoolExecutor更轻量、启动快、内存占用低。比如并发请求100个网页,用线程池通常比进程池快2–3倍。

  • 典型场景:http请求、日志写入、redis操作、csv解析(含读取)
  • 注意点:单个IO操作若耗时极长(如超30秒),需设timeout并捕获异常,避免线程卡死

看任务是否持续占用CPU计算

如果任务主要做数学运算、图像处理、加密解密、大规模列表推导等,属于CPU密集型。python的GIL会限制多线程真正并行,此时ProcessPoolExecutor能绕过GIL,利用多核提升吞吐。但进程启动慢、内存复制开销大,不适合短任务或数据量大的参数传递。

  • 典型场景:科学计算、视频帧处理、批量pdf文本提取、蒙特卡洛模拟
  • 注意点:传参尽量轻量;复杂对象建议用functools.partial封装成可序列化函数

混合场景可以组合使用

实际项目常同时存在IO和CPU操作。例如“下载图片→本地缩略图处理”,可先用线程池并发下载,再将下载好的文件路径交给进程池做CPU密集的图像处理。避免在线程中直接调用CPU-heavy函数,否则会阻塞整个线程池。

立即学习Python免费学习笔记(深入)”;

  • 推荐结构:线程池负责IO部分,结果通过队列或列表交由进程池二次处理
  • 不推荐:在线程里调subprocess.run()启动新进程——管理复杂且易出错

别忽略小任务和资源限制

任务平均执行时间低于10ms,或总并发数不到5,用同步执行反而更稳。盲目上池子可能因调度开销得不偿失。另外,进程池数量不宜超过os.cpu_count(),线程池一般控制在min(32, os.cpu_count() * 4)以内,避免系统级线程/进程竞争。

  • 调试技巧:用concurrent.futures.as_completed()观察各任务耗时分布,识别瓶颈类型
  • 替代思路:对极高并发IO(如万级连接),考虑asyncio + aiohttp,比线程池更省内存
text=ZqhQzanResources