multiprocessing对纯计算密集型任务有效,但对Web+计算混合任务需分离逻辑:Web请求(I/O密集)应在主线程或asyncio中完成,仅将真正CPU密集的后续处理(如大JSON解析、数值拟合)交由ProcessPoolExecutor并行,且postprocess必须是纯函数;requests session等不可pickle对象不可传入子进程,否则报错或性能反降。

multiprocessing 对纯计算密集型任务有效,但对“密集计算型Web任务”要先拆开看——它不是单一类型:Web部分(如HTTP请求)是I/O密集,计算部分才是CPU密集。直接套用 multiprocessing 很可能更慢,甚至出错。
为什么 Web + 计算混合任务不能直接上 ProcessPoolExecutor
-
requests或httpx客户端对象不可 pickle,传进进程池会报AttributeError: Can't pickle <class 'requests.sessions.Session'> - 每个子进程重复初始化 session、重连、证书验证,开销远超收益
- 如果任务中含少量计算+大量等待(比如调 API → 等响应 → 解析 JSON → 做简单统计),本质仍是 I/O 密集,
multiprocessing反而因进程启动和序列化拖累整体速度
如何正确分离 Web 和计算逻辑
- 把「发请求 + 收响应」留在主线程或
asyncio中完成,只把真正耗 CPU 的后续处理(如解析大 JSON、数值拟合、图像缩放)扔给ProcessPoolExecutor - 示例结构:
responses = await asyncio.gather(*[fetch(url) for url in urls]) # 异步批量拉数据<br>results = list(pool.map(postprocess, responses)) # 仅计算部分并行
-
postprocess必须是纯函数:只依赖输入参数,不读全局变量、不改外部状态、不调用不可序列化对象
pool.map vs pool.imap_unordered 在 Web 场景下的取舍
- 用
pool.map:适合结果需严格保序(比如按 URL 列表顺序存数据库),但内存随响应数量线性增长,350 个 10MB 响应体就吃掉 3.5GB 内存 - 用
pool.imap_unordered:结果乱序返回,但可边算边写、流式处理;尤其适合写入文件或数据库时避免堆积 - 别用
apply_async+ callback:容易漏.get()或忘记pool.close()/pool.join(),子进程卡住不退出是常见故障
进程数设多少才不翻车
- 默认
os.cpu_count()是陷阱:如果每个计算任务本身已占满内存(比如加载 2GB 模型),开 8 进程=8×2GB=16GB,触发系统 swap,反而比单进程还慢 - 实测建议:从
max_workers=2开始,观察内存占用和 CPU 利用率,再逐步加;超过物理核心数后收益通常递减 - Windows/macOS 下必须确保入口有
if <strong>name</strong> == "<strong>main</strong>":,否则子进程反复 import 主模块导致无限 fork
真正卡点不在怎么开进程,而在哪一段该交给进程——Web 请求永远不该进 multiprocessing,只有拿到 raw data 后的纯计算环节才值得并行。漏掉这个边界,再多的 Pool 配置都白搭。


















