You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

列表并行求和场景下ThreadPoolExecutor为何更高效?如何优化ProcessPoolExecutor?

ThreadPoolExecutor 优于 ProcessPoolExecutor 的原因及 ProcessPool 优化方案

为什么 ThreadPoolExecutor 效率更高?

  • 进程的固有开销远大于线程:Python中每个进程拥有独立的内存空间,创建、销毁进程以及进程间通信(IPC)的成本极高。你的任务是简单的整数加法,计算量极小,进程的启动/通信开销完全盖过了并行计算的收益,反而拖慢了整体速度。而线程共享父进程内存,创建、切换、通信的开销都可以忽略不计。
  • 循环内重复创建 Executor 放大了进程开销:代码在每次循环中都新建ProcessPoolExecutor,意味着每次循环都要重新创建一组子进程,这个初始化过程的成本非常高。相比之下,ThreadPoolExecutor创建线程的成本极低,重复创建的影响微乎其微。
  • 任务粒度太细:单个加法任务的执行时间几乎可以忽略,进程调度和IPC的时间远超过任务本身的执行时间。ProcessPool适合处理CPU密集型且任务粒度较大的工作,这种细粒度任务完全发挥不出它的优势。

如何优化 ProcessPoolExecutor 的性能?

1. 复用进程池,避免重复创建

把ProcessPoolExecutor的创建移到循环外部,全程复用同一组进程,避免每次循环都重新初始化进程的开销。

2. 避免跨进程访问外部变量

当前代码中group_cont访问外部的add_list,ProcessPool会把这个列表序列化后传到子进程,每次循环都要传递数据,增加了额外开销。应该直接把需要相加的数值作为参数传给函数。

3. 增大任务粒度

将多个加法任务打包成一个批次,减少进程调度和IPC的次数。比如一次处理多个数对的加法,而不是单个。

4. 合理设置进程池大小

默认进程池大小是CPU核心数(你的8核),过多的进程会增加调度开销,对于细粒度任务,可以适当减少进程数量,比如设置为4。


优化后的代码示例

import concurrent.futures
import time

add_list = list(range(100))
temp_len = len(add_list)

loop_start = time.time()

# 复用进程池,放在循环外面
with concurrent.futures.ProcessPoolExecutor(max_workers=4) as executor:
    while temp_len > 1:
        is_odd = temp_len % 2
        group_len = temp_len // 2 + is_odd
        # 直接生成需要相加的数值对,而不是索引,避免子进程访问外部列表
        groups = [(add_list[2*i], add_list[2*i+1]) for i in range(group_len - is_odd)]
        
        last = add_list[-1] if is_odd else None
        
        def add_pair(pair):
            return pair[0] + pair[1]
        
        results = executor.map(add_pair, groups)
        
        add_list = list(results)
        if is_odd:
            add_list.append(last)
        temp_len = group_len

loop_end = time.time()
print(f'Time: {round(loop_end - loop_start, 3)}')

内容的提问来源于stack exchange,提问作者Wei-jia Huang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 03:17:07