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,并行版本依然会因前面的核心问题更慢。
修复建议
- 合并细粒度任务:将多个小任务打包为大任务,减少并行调度开销。例如每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)
- 改用进程并行:对于CPU密集型任务,使用
prefer="processes"(或默认的loky后端)绕过GIL限制。注意进程数不要超过CPU核心数的1-2倍,48个进程会导致严重的上下文切换,反而降低效率。 - 去掉不必要的列表生成:直接用
range(0,10000000)代替list(range(...)),避免提前占用大量内存。 - 避免无意义的并行:如果任务本身足够轻量,串行反而比并行高效,不要为了并行而并行。
内容的提问来源于stack exchange,提问作者Orestis
相关产品推荐
相关产品推荐

