如何解决Python多进程开销过高、新增核心耗时反而上升的问题
问题成因
- 核心原因是高频访问
multiprocessing.Manager创建的共享字典:Manager的共享对象实际存储在独立的管理进程中,所有子进程对该对象的读取、遍历操作都需要跨进程IPC通信,且默认加锁避免并发冲突。你的代码在循环中反复遍历共享字典的values(),进程数越多,IPC请求和锁竞争越严重,通信开销远超过计算本身的开销,导致耗时随核心数上升。 - 次要问题1:
jobs列表未重置,每次测试不同进程数时,都会把新进程追加到原有列表中,join操作会遍历所有历史进程,增加无意义开销。 - 次要问题2:总计算量过小,单进程完成全部计算的耗时本身就极低,多进程的启动、通信开销直接覆盖了并行收益。
优化方案
- 只读数据避免使用共享对象:你的
mp_dict是只读的,不需要跨进程同步修改,直接将普通字典作为参数传给子进程,子进程会自动拿到副本,完全避免IPC开销。 - 每次测试前重置
jobs列表,避免累加历史进程。 - 减少共享对象的使用:返回结果可通过
multiprocessing.Pool的map系列方法直接获取,不需要用Manager.dict存储返回值。 - 合理控制任务粒度:如果实际业务的单任务计算量很小,可合并多个小任务为一个大任务再分配给进程,保证计算耗时远大于进程通信开销。
优化后代码示例
import time import multiprocessing as mp import numpy as np def test_fun(args): iter_nr, local_dict = args dumm = 0 for j in range(iter_nr): for val in local_dict.values(): dumm += val return dumm if __name__ == '__main__': # 构造普通只读字典,不需要共享 local_dict = {str(i):1 for i in range(100)} nproc = [2,4,6,8,10,12,16,20] nr_iter = 2*4*6*8*10 print('Total number of iterations: ', nr_iter) for n_proc in nproc: per_proc_iter = int(nr_iter / n_proc) print('Nr CPUs: ', n_proc) print('Nr iterations per process: ', per_proc_iter) # 构造进程池的任务参数 tasks = [(per_proc_iter, local_dict) for _ in range(n_proc)] start_time = time.time() with mp.Pool(n_proc) as pool: res = pool.map(test_fun, tasks) end_time = time.time() print(round(end_time - start_time, 3), 'sec')
优化后运行耗时会随核心数增加明显下降,符合并行计算预期。
内容的提问来源于stack exchange,提问作者Jaro
相关产品推荐
相关产品推荐

