如果你在内存中画出数组的图像,你会更好地理解这个问题:
Y ->
X xxxxx ...
| xxxxx
v xxxxx
.
.
您所访问的地址在Y方向上呈线性增长(345、345+1、345+2...),但如果Y很大,则在X方向上跳跃非常剧烈(345、345+X、345+X*2)。由于缓存加载内存块,当Y足够大时,您将很快跳出它们,但在沿Y方向行走时始终会在缓存页面中,直到必须刷新缓存为止。此外,请注意,在使用动态分配时,这种效果可能更加极端。使用完全优化的以下程序给我以下输出(以秒为单位的时间)。
0.615000
9.878000
编辑:其他有趣的措施:
将数组代码替换为int array[X][Y];
将使用栈内存,其受限制,因此您无法测试更大的X/Y值,但速度也非常快:
0.000000
0.000000
将 int array[X][Y];
作为全局变量使用会使用一块堆内存,并且速度较慢。因此,即使没有动态分配,第一种情况仍然要好得多:
0.929000
8.944000
使用 X=1500,Y=1500 可以显示即使使用较小的数组也可以测量效果:
0.008000
0.059000
编辑2:还要注意,正如jalf在你的问题评论中所说,代码还有其他可能的优化。使用这种优化确实将速度几乎提高了一倍(X=Y=10000时为0.453秒):
// an even faster way to access the array
for (int x = 0; x < X; x++) {
int* arrayptr = array[x];
for (int y = 0; y < Y; y++, arrayptr++)
*arrayptr = x;
}
代码:(请注意,您也可以使用此方法来测量差异情况,除了大X和Y的情况外,差异不应该那么明显。正如其他人已经说过的,测量这个值将使您受益匪浅)。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define X 10000
#define Y 10000
int main() {
int** array = new int*[X];
for (int x = 0; x < X; x++) {
array[x] = new int[Y];
}
double c = clock();
for (int x = 0; x < X; x++)
for(int y = 0; y < Y; y++)
array[x][y] = x;
printf("%f\n", (clock() - c) / CLOCKS_PER_SEC);
c = clock();
for (int y = 0; y < Y; y++)
for (int x = 0; x < X; x++)
array[x][y] = x;
printf("%f\n", (clock() - c) / CLOCKS_PER_SEC);
for (int x = 0; x < X; x++) {
delete(array[x]);
}
delete(array);
}