标准三层for循环矩阵乘法需通过OpenMP按行或分块并行化以提升多核性能:行拆分用#pragma omp parallel for实现无竞争写入;分块则复用局部数据提高缓存命中率;避免小矩阵、细粒度拆分及动态调度等性能陷阱。

直接用标准三层 for 循环做矩阵乘法(i-j-k 顺序)是串行的,无法自动利用多核。要提升多核 CPU 上的速度,核心不是改循环结构本身,而是把“计算任务”按逻辑切开,让多个线程各自负责一部分独立子任务,再合并结果。关键在于拆分方式要避免数据竞争、减少同步开销,并尽量保持缓存友好。
按输出矩阵 C 的行或块分配任务
这是最常用、实现简单且效果稳定的方式。C 是 M×N 矩阵,每个元素 C[i][j] 的计算只依赖 A 的第 i 行和 B 的第 j 列,不同行之间完全独立。
- 让每个线程处理 C 的若干连续行(例如每线程负责 4 行),内部仍用标准 j-k 两层循环计算
- 使用 OpenMP 时只需在最外层 i 循环加
#pragma omp parallel for,编译器自动调度 - 避免对 C[i][j] 做原子写入——因为每个线程写的是不同行,内存地址不重叠,无需锁或原子操作
采用二维分块(tiling)提升缓存命中率
单纯按行并行能利用多核,但若矩阵很大,频繁访问 B 的列会导致大量缓存失效。分块把 A 和 B 都切成小矩形块,在线程内复用局部数据。
- 设定块大小如 TILE = 16,外层用 m/n 步进循环遍历 C 的每个 TILE×TILE 块
- 每个线程加载 A 的一行块 + B 的一列块到本地临时数组,再用三层小循环完成该块内所有乘加
- 这样 B 的同一块被多次复用,显著降低从主存读取次数
- OpenMP 可套在最外层 m-n 循环上,每个线程处理一个或多个完整 tile
避免常见性能陷阱
并行不一定更快,错误拆分反而拖慢速度。
- 不要为小矩阵(如 100×100 以下)强行并行——线程创建/调度开销可能超过计算收益
- 避免细粒度拆分(如每个线程只算一个 C[i][j]):线程数远超核心数,上下文切换成本高
- 禁用默认的
schedule(dynamic),改用schedule(static)或指定 chunk size,防止负载不均 - 确保 A、B、C 内存按行优先(C-style)连续布局,否则 B 的列访问会变成跨页随机读
一个轻量级 OpenMP 示例(基于行拆分)
假设 A[M][K]、B[K][N]、C[M][N] 已分配好连续内存:
#pragma omp parallel for schedule(static) for (int i = 0; i <p>这段代码在 4 核 CPU 上通常可获得接近 3.5 倍加速,前提是矩阵足够大(如 M=N=K≥2000)且未开启过度优化干扰向量化。</p>










