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

Python concurrent.futures多进程池无法随处理器数量扩展问题

问题分析:多进程执行耗时反而增加的原因与优化

核心原因拆解

你的测试结果不符合预期,本质是三个关键因素共同作用的结果:

1. 任务量随进程数线性增长

你的process函数中,iterobj = range(num_jobs)同时搭配max_workers=num_jobs,这意味着每增加一个进程,就会多执行一次test_multi函数。比如1进程执行1次列表构建,10进程执行10次完整的列表构建——总工作量是原来的10倍,耗时自然会大幅上升,这并非多进程本身的问题,而是任务逻辑设计错误。

2. 列表拼接的低效操作

test = test + [i]是性能杀手:每次拼接都会创建新列表并复制所有已有元素,时间复杂度为O(n²)。单进程下这已经导致52秒的耗时,多进程下每个进程都在重复这个高开销操作,进一步放大了总耗时。

3. Windows进程创建的额外开销

Windows下ProcessPoolExecutor使用spawn方式创建进程,每个子进程都需要重新加载Python解释器、导入模块。当任务数量多且单个任务耗时不够长时,这部分初始化开销会显著拉高总耗时。

优化方案

1. 修正任务逻辑:并行拆分单个任务

如果目标是用多进程加速单个列表的构建,需要将任务拆分为多个子区间,让不同进程协作完成,而非每个进程单独构建完整列表:

from datetime import datetime
import concurrent.futures

def test_multi(start, end):
    starttime = datetime.utcnow()
    # 用内置list(range)替代低效循环拼接,直接生成子区间列表
    test = list(range(start, end))
    return (datetime.utcnow()-starttime)

def process(num_workers):
    total_elements = 200000
    # 拆分任务为多个子区间
    chunk_size = total_elements // num_workers
    chunks = [(i*chunk_size, (i+1)*chunk_size) for i in range(num_workers)]
    # 处理最后一个区间的剩余元素
    if total_elements % num_workers != 0:
        chunks[-1] = (chunks[-1][0], total_elements)
    
    with concurrent.futures.ProcessPoolExecutor(max_workers=num_workers) as ex:
        results = list(ex.map(lambda x: test_multi(*x), chunks))
    
    return results

if __name__ == '__main__' :
    max_processors = 10
    
    for i in range(max_processors):      
        num_workers = i+1
        starttime = datetime.utcnow()
        result = process(num_workers)
        finishtime = datetime.utcnow()-starttime
        if i == 0:
            chng = 0
            total = 0
            firsttime = finishtime
        else:
            chng = finishtime/lasttime*100 - 100
            total = finishtime/firsttime*100 - 100
        lasttime = finishtime
        print(f'Multi took {finishtime} for {num_workers} processes changed by {round(chng,2)}%, total change {round(total,2)}%')

2. 优化列表构建方式

无论是否用多进程,都要替换低效的列表拼接:

  • 用test.append(i)替代test = test + [i],时间复杂度降为O(n)
  • 直接用list(range(200000))生成列表,这是Python内部优化的C实现,速度会提升几个数量级(单进程耗时从52秒降到毫秒级)

3. 合理控制进程数

即使是48核机器,进程数也无需开到48——进程调度、上下文切换会产生额外开销,通常设置为CPU核心数或核心数+1即可,避免过度调度。

内容的提问来源于stack exchange,提问作者WGee

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 19:20:30