矩阵乘法性能优化关键在于内存访问顺序匹配缓存行为,而非循环结构本身;标准三重循环中,i、j、k 的嵌套顺序直接影响缓存命中率,需按行优先或分块策略调整访问模式以提升性能。

双重for循环手写矩阵乘法本身不难,关键在于让内存访问模式匹配硬件缓存行为,否则即使算法正确,性能也可能差几倍。优化核心不是“怎么写循环”,而是“按什么顺序访问内存”。
明确矩阵乘法的计算逻辑
标准三重循环实现如下(以 C/Java 风格为例): ```java for (int i = 0; i 所以单纯“手写”不够,必须调整访问步长与物理布局对齐。优化内存访问步长:让每次读取都利用 cache 行
现代 CPU 从内存加载数据时,会一次性载入一个 cache line(通常 64 字节)。如果能连续访问同一 cache line 内的多个元素,效率就高。- 对于行优先存储(C、Java、Python 的 list of lists 默认行为),同一行的元素是连续存放的;
- 因此,应尽量让内层循环遍历同一行,即访问
A[i][k]和B[k][*]时,让B的访问也落在连续内存上。
✅ 正确做法:交换 j 和 k 循环,使 B 按行访问
for (int i = 0; i < n; i++) {
for (int k = 0; k < m; k++) {
int a_ik = A[i][k]; // 提前读一次,复用
for (int j = 0; j < p; j++) {
C[i][j] += a_ik * B[k][j]; // B[k][j]:固定 k,j 增加 → 连续访问 B 的第 k 行
}
}
}这样:
-
A[i][k]是单次读取,被内层复用p次; -
B[k][j]随j递增 → 访问B[k][0],B[k][1],B[k][2]… 连续内存,cache 利用率高; -
C[i][j]同样是连续写入第i行,友好。
这个顺序常称 “i-k-j” 或 “行主序优化版”,比原始 i-j-k 快 2–5 倍(取决于矩阵大小和 cache 容量)。
进一步减少访存开销:缓存中间变量 & 避免重复寻址
- 把 `A[i][k]` 提到内层外,避免每次 `j` 循环都重新读 `A[i][k]`; - 把 `B[k]` 整行缓存为局部指针或数组引用(如 `int[] bRow = B[k]`),省去 `B[k][j]` 中每次计算 `k * width + j` 的偏移; - `C[i]` 也可缓存为 `int[] cRow = C[i]`,写入更直接。for (int i = 0; i < n; i++) {
int[] cRow = C[i];
for (int k = 0; k < m; k++) {
int a_ik = A[i][k];
int[] bRow = B[k]; // 一行数据,连续
for (int j = 0; j < p; j++) {
cRow[j] += a_ik * bRow[j];
}
}
}补充:若语言支持,用一维数组替代二维数组
二维数组语法方便,但 `A[i][k]` 实际要算 `i * cols + k`,多一次乘法+加法。用一维模拟可显式控制步长:// A[n][m] → a[i * m + k]
// B[m][p] → b[k * p + j]
// C[n][p] → c[i * p + j]
for (int i = 0; i < n; i++) {
for (int k = 0; k < m; k++) {
int a_val = a[i * m + k];
int b_base = k * p;
for (int j = 0; j < p; j++) {
c[i * p + j] += a_val * b[b_base + j];
}
}
}此时所有索引都是线性递增,无分支、无间接跳转,CPU 流水线更友好。
不复杂但容易忽略

















