Python multiprocessing多进程代码运行速度远慢于单线程问题求解
问题原因分析
- 错误使用同步阻塞的
pool.apply()接口pool.apply()是同步执行方法,每次调用都会阻塞主进程,等待对应任务执行完成返回结果后才会继续执行后续代码。你在循环中调用1000万次apply(),本质还是串行执行所有任务,没有任何并行效果,反而每次调用都要额外付出进程调度、跨进程数据传输的开销,所以速度远低于纯串行实现。 - 任务粒度过小,额外开销远超计算收益
你设定的每个任务仅处理长度为5的一行数组,单次任务的计算量极小。而Python多进程受GIL限制,跨进程传递参数、返回结果都需要做序列化/反序列化操作,1000万次任务的额外开销总和已经远远超过了并行计算能带来的收益,自然会出现越改越慢的情况。
优化方案
- 替换任务提交接口,使用
pool.starmap()批量提交任务,避免循环单次提交的调度开销;如果需要异步执行可以选择starmap_async()。 - 调整任务粒度,把大数组拆分为和CPU核心数相近的大块,每个进程处理一个大块,大幅降低跨进程通信的占比。
- 优先使用numpy向量化操作替代Python循环,numpy内置运算本身已经做了底层优化,哪怕串行执行速度也远快于手写Python循环,小计算量场景下不需要引入多进程就能满足性能需求。
优化后的多进程实现示例
import time import multiprocessing as mp import numpy as np def how_many_within_range(chunk, minimum, maximum): # 直接用numpy向量化计算,替代循环 return np.sum((chunk >= minimum) & (chunk <= maximum), axis=1) if __name__ == '__main__': data = np.random.randint(0, 10, size=[10000000, 5]) print(data[:5]) start_time = time.perf_counter() # 拆分数组为和CPU核心数相同的块 cpu_count = mp.cpu_count() chunks = np.array_split(data, cpu_count) with mp.Pool(cpu_count) as pool: # 批量提交任务,每个任务处理一个大块 results = pool.starmap(how_many_within_range, [(chunk, 4, 8) for chunk in chunks]) # 合并结果 results = np.concatenate(results) print(f'Time elapsed: {time.perf_counter() - start_time}') print(results[:5])
如果你不需要多进程,直接用向量化的numpy运算,速度会更快:
start_time = time.perf_counter() results = np.sum((data >=4) & (data <=8), axis=1) print(f'Time elapsed: {time.perf_counter() - start_time}')
内容的提问来源于stack exchange,提问作者MrLatinNerd
相关产品推荐
相关产品推荐

