Python进程池教程_多核并行计算实践

Python进程池是利用多核CPU并行计算最常用方式,基于multiprocessing.Pool自动管理子进程,适合计算密集型任务,可绕过GIL限制,但需注意参数序列化开销及内存不共享特性。

Python进程池是利用多核CPU进行并行计算最常用、最稳妥的方式,核心在于用 multiprocessing.Pool 自动管理子进程,避免手动创建/通信的复杂性。它适合计算密集型任务(如数值运算、图像处理、模型推理),而非I/O密集型(此时更推荐异步或线程池)。

为什么选进程池而不是多线程?

CPython存在全局解释器锁(GIL),导致多线程无法真正并行执行CPU密集型代码。而进程拥有独立内存空间和Python解释器,能绕过GIL,充分发挥多核性能。

注意:进程间不共享内存,传参和返回值会序列化(pickle),因此对象需可被pickle,且大数据传递有开销。

基础用法:map、apply 和 starmap

map 最常用,适用于单参数函数批量执行:

  • 自动将可迭代对象切分,分发给多个进程
  • 结果按输入顺序返回(阻塞等待全部完成)

示例:

def square(x): return x * x
with multiprocessing.Pool(4) as pool:
  result = pool.map(square, [1, 2, 3, 4, 5])
print(result) # [1, 4, 9, 16, 25]

apply 类似同步调用,只运行一次,适合需要立即返回结果的场景;apply_async 是其异步版本,返回 AsyncResult 对象,可用 .get() 获取结果。

starmap 用于多参数函数,参数以元组形式提供:

def add(a, b): return a + b
with Pool() as p:
  res = p.starmap(add, [(1,2), (3,4), (5,6)])

进阶技巧:控制并发与错误处理

初始化 Pool 时可指定 processes(默认为 CPU 核心数),也可设为 None 让系统自动判断。

  • maxtasksperchild 限制每个子进程处理的任务数,防止内存泄漏或状态累积
  • 捕获异常:map 默认传播第一个出错任务的异常;若想收集所有异常,改用 map_async + result.get(timeout=...) 并配合 try/except
  • 关闭池后必须调用 pool.close()pool.join(),或使用 with 语句自动管理

实战建议:何时用、怎么优化

适合场景:单次耗时 > 0.1 秒的纯计算任务;输入数据可分割、无强依赖;函数无全局状态修改。

  • 避免频繁小任务:进程启动/通信开销可能抵消并行收益;可先合并小任务再提交
  • 大数组传递?优先用 multiprocessing.shared_memory(Python 3.8+)或 numpy.memmap 减少拷贝
  • 调试阶段建议先用 Pool(1) 或直接调函数,确认逻辑正确后再开启多进程
  • Windows *意将入口保护写成 if __name__ == '__main__':,防止子进程重复执行主模块