Python多进程执行NumPy运算加速不达预期的瓶颈诊断
相位检索算法多进程加速性能异常问题
问题概述
- 开发中正在实现相位检索算法(phase retrieval algorithm),当前遇到多进程加速效果远低于预期的问题。
- 算法核心逻辑是对大小为10-100MB量级的NumPy矩阵执行迭代浮点运算,运行过程无任何IO操作;并行方案采用
multiprocessing.Process启动多个完全独立的迭代流程,进程间不存在任何通信交互。 - 测试所用计算节点配置为40个物理CPU核心(支持80超线程)、250GB内存。基于无进程通信、无IO调用的前提,最初预期可达到40-80倍的加速比,但实际40个并行进程场景下仅获得约20倍加速。
已开展的排查与现象
- 分别在1进程、40进程、70进程并行场景下,对随机采样的进程使用
cProfile做性能分析,结果显示迭代流程各子模块的耗时占比基本稳定,但单个操作的绝对耗时大幅升高:70个并行进程场景下,简单的numpy.conjugate调用耗时可达单进程场景的4-5倍,对应Snakeviz性能分析可视化结果已留存。 - 已排除内存容量不足问题:节点250GB内存完全满足运行需求。
- 单进程运行时对应CPU核心占用始终接近100%;1、40、70并行进程场景下,节点整体CPU占用分别约为1%、50%、90%。
- 目前初步怀疑性能瓶颈与内存带宽有关,需要对应的验证排查方法。
最小可复现代码
仅调用numpy.conjugate()即可复现该性能问题,复现代码如下:
from multiprocessing import Process, Queue import time import numpy as np import timeit import os os.environ['OPENBLAS_NUM_THREADS'] = '1' os.environ['MKL_NUM_THREADS'] = '1' def f(q): a = np.random.rand(64,254,128) + 1.j*np.random.rand(64,254,128) start = time.time() for i in range(10): a.conj() duration = time.time()-start q.put(duration) def speed_test(number_of_processes=1): process_list=[] queue = Queue() # 启动对应数量的进程 for p_id in range(number_of_processes): p = Process(target=f,args=(queue,)) process_list.append(p) p.start() # 等待所有进程执行完毕 for p in process_list: p.join() output = [] while queue.qsize() != 0: output.append(queue.get()) return np.mean(output) if __name__ == '__main__': p1 = speed_test(number_of_processes=1) p40 = speed_test(number_of_processes=40) p70 = speed_test(number_of_processes=70) print('\n 1进程耗时 {} 秒\n 40进程耗时 {} 秒 \n 70进程耗时 {} 秒'.format(p1,p40,p70))
复现结果
- 测试复现结果显示,70核并行时上述代码中
numpy.conjugate()的运行速度比单核运行慢5倍,与预期性能差异极大。 - 目前已补充不同数组大小、更大矩阵场景下的耗时对比数据,可按需提供更多问题定位所需的运行数据,现寻求该性能问题的根因定位与可行解决方案。
内容的提问来源于stack exchange,提问作者Tim
相关产品推荐
相关产品推荐

