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

Python中joblib并行计算异常:非并行正常但并行无输出且耗时极长

问题:joblib并行计算远慢于串行循环甚至无输出

用户测试代码如下:

import time
from joblib import Parallel, delayed

def fun(i):
    return i**2


start = time.time()
for i in list(range(0,10000000,1)):
    print(fun(i))
end = time.time()
print(end - start)


start = time.time()
Parallel(n_jobs=48,prefer="threads")(delayed(fun)(i) for i in list(range(0,10000000,1)))  
end = time.time()
print(end - start)

串行循环耗时37秒,但并行版本运行6分钟以上仍无输出,求问题原因。


核心问题分析

  • 任务粒度太小,并行开销远超收益:fun(i)仅执行i**2这一极轻量操作,单任务耗时微乎其微。但并行计算需要完成线程创建、任务分配、线程通信、结果汇总等操作,这些开销远大于单个任务的执行时间,48个线程频繁切换反而会拖慢整体速度。
  • 线程GIL限制:使用prefer="threads"时,Python的全局解释器锁(GIL)会限制同一时刻只有一个线程执行Python字节码。对于这类CPU密集型轻量任务,线程并行完全无法发挥优势,反而因GIL切换成本导致效率暴跌。
  • 不必要的内存开销:list(range(0,10000000,1))会一次性生成1000万个元素的列表,占用大量内存,并行迭代时会额外增加数据传递成本。
  • 串行版本的print干扰对比:串行版本的37秒耗时里,大部分时间花在print这个IO操作上,而并行版本没有print,但即使去掉串行的print,并行版本依然会因前面的核心问题更慢。

修复建议

  1. 合并细粒度任务:将多个小任务打包为大任务,减少并行调度开销。例如每1000个i为一组计算:
def fun_batch(i_list):
    return [x**2 for x in i_list]

# 分割任务
batch_size = 1000
total = 10000000
batches = [range(i, min(i+batch_size, total)) for i in range(0, total, batch_size)]

start = time.time()
Parallel(n_jobs=8, prefer="processes")(delayed(fun_batch)(batch) for batch in batches)
end = time.time()
print(end - start)
  1. 改用进程并行:对于CPU密集型任务,使用prefer="processes"(或默认的loky后端)绕过GIL限制。注意进程数不要超过CPU核心数的1-2倍,48个进程会导致严重的上下文切换,反而降低效率。
  2. 去掉不必要的列表生成:直接用range(0,10000000)代替list(range(...)),避免提前占用大量内存。
  3. 避免无意义的并行:如果任务本身足够轻量,串行反而比并行高效,不要为了并行而并行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 02:20:27