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

大矩阵Numpy多进程性能无提升原因咨询(Ryzen 9 3900X)

大矩阵多进程场景下性能无提升的原因解析

实验背景与现象

我用Python测试多进程对随机矩阵乘法的性能加速比,任务完全独立无对象共享。原本预期不同矩阵尺寸的性能曲线一致,但结果显示矩阵尺寸较大(80、160)时,增加进程数几乎无法提升性能。

我的CPU为AMD Ryzen™ 9 3900X,规格如下:

Product Family: AMD Ryzen™ Processors
Product Line: AMD Ryzen™ 9 Desktop Processors
# of CPU Cores: 12
# of Threads: 24
Max. Boost Clock: Up to 4.6GHz
Base Clock: 3.8GHz
L1 Cache: 768KB
L2 Cache: 6MB
L3 Cache: 64MB

实验结果表现为:小矩阵(5、10、20、40)随进程数增加加速比明显提升,大矩阵(80、160)加速比几乎维持在1左右。

实验代码

主测试脚本

import numpy as np
import pickle
from dataclasses import dataclass
import time
import multiprocessing
import os
import subprocess
import numpy as np


def split_number(n_total, n_split):
    return [n_total // n_split + (1 if x < n_total % n_split else 0) for x in range(n_split)]


def task(args):
    n_iter, idx, matrix_size = args
    #cores = "{},{}".format(2 * idx, 2 * idx+1)
    #os.system("taskset -p -c {} {}".format(cores, os.getpid()))
    for _ in range(n_iter):
        A = np.random.randn(matrix_size, matrix_size)
        for _ in range(100):
            A = A.dot(A)


def measure_time(n_process: int, matrix_size: int) -> float:
    n_total = 100
    assigne_list = split_number(n_total, n_process)
    pool = multiprocessing.Pool(n_process)
    ts = time.time()
    pool.map(task, zip(assigne_list, range(n_process), [matrix_size] * n_process))
    elapsed = time.time() - ts
    return elapsed


if __name__ == "__main__":
    n_experiment_sample = 5
    n_logical = os.cpu_count()
    n_physical = int(0.5 * n_logical)
    result = {}
    for mat_size in [5, 10, 20, 40, 80, 160]:
        subresult = {}
        result[mat_size] = subresult
        for n_process in range(1, n_physical + 1):
            elapsed = np.mean([measure_time(n_process, mat_size) for _ in range(n_experiment_sample)])
            subresult[n_process] = elapsed
            print("{}, {}, {}".format(mat_size, n_process, elapsed))
    with open("result.pkl", "wb") as f:
        pickle.dump(result, f)

绘图脚本

import numpy as np
import matplotlib.pyplot as plt
import pickle
with open("result.pkl", "rb") as f:
    result = pickle.load(f)

fig, ax = plt.subplots()

for matrix_size in result.keys():
    subresult = result[matrix_size]
    n_process_list = list(subresult.keys())
    elapsed_time_list = np.array(list(subresult.values()))
    speedups = elapsed_time_list[0] / elapsed_time_list
    ax.plot(n_process_list, speedups, label=matrix_size)

ax.set_xlabel("number of process")  
ax.set_ylabel("speed up compared to single process")  

ax.legend(loc="upper left", borderaxespad=0, fontsize=10, framealpha=1.0)
plt.show()

原因分析

1. 内存带宽瓶颈

大矩阵运算对内存带宽的需求远高于小矩阵:

  • 以160x160的float64矩阵为例,单个矩阵占用160*160*8 = 204800字节 ≈ 200KB,但每次矩阵乘法需要频繁读写内存中的矩阵数据,加上循环100次的迭代,会产生海量的内存访问请求。
  • 当多进程同时运行时,所有进程都会争抢CPU的内存带宽资源。Ryzen 9 3900X的内存带宽是固定的(DDR4-3200约51GB/s),当多个进程同时发起内存访问时,带宽会被占满,此时CPU核心即使空闲也无法获取足够的数据,导致计算等待内存数据,性能无法随进程数提升。

2. CPU缓存利用率下降

  • 小矩阵可以完全放入L2或L3缓存中,运算时无需频繁从主存读取数据,CPU核心能高效利用缓存进行计算,多进程并行时每个核心的缓存都能发挥作用,加速比明显。
  • 大矩阵(比如160x160)的尺寸超过了单核心L2缓存(每个核心512KB L2,3900X共12核心,总L2 6MB),甚至接近L3缓存总容量(64MB)。当多进程同时处理大矩阵时,缓存会被多个进程的矩阵数据填满,频繁出现缓存失效,不得不从主存加载数据,进一步加剧内存带宽的压力,导致并行效率骤降。

3. 浮点运算单元(FPU)与内存带宽的平衡

  • 小矩阵运算时,CPU的FPU是瓶颈:计算量小,内存访问少,多进程可以充分利用多个FPU核心,提升性能。
  • 大矩阵运算时,内存带宽成为瓶颈:FPU的计算能力远超过内存数据供给速度,即使增加进程数,FPU大部分时间处于等待数据的状态,无法发挥并行计算的优势。

验证建议

  • 可以尝试绑定进程到物理核心(取消代码中taskset相关注释),减少线程调度开销,但本质上无法解决内存带宽瓶颈。
  • 测试更大的内存带宽配置(比如升级到DDR4-3600或更高),观察大矩阵的并行性能是否有提升。
  • 减少每个进程的矩阵运算循环次数,降低内存访问压力,看并行加速比是否恢复。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 21:51:16