是否首先访问第一个维度而不是访问二维数组的第二个维度?

时间:2010-09-25 11:39:04

标签: c++ c

这是代码,

int array[X][Y] = {0,};

// 1 way to access the data
for (int x = 0; x < X; x++)
  for(int y = 0; y < Y; y++)
    array[x][y] = compute();

// the other way to access the data
for (int y = 0; y < Y; y++)
  for (int x = 0; x < X; x++)
    array[x][y] = compute();

自CPU缓存(L1,L2?)优化以来,第一种方式是否比第二种方式更有效?换句话说,即使对于RAM,是否优选顺序访问模式?

5 个答案:

答案 0 :(得分:5)

如果你在内存中绘制阵列的图片,你会更好地理解这一点:

  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

EDIT2:另请注意,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();  

  // 1 way to access the data
  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();  

  // the other way to access the data
  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);
}

答案 1 :(得分:3)

是。特别是如果行适合缓存行。如果您使用了第二种方法,并且数组中有足够大的行,则没有缓存局部性,并且缓存行将不断被删除。

答案 2 :(得分:2)

是的,第一个更快。在存储器矩阵中存储一行接一行(行主要),因此相邻元素将更有可能在虚拟存储器中的同一页面中(整个页面被带到高速缓存,因此访问时间更短)。

另一种方法会为更大的矩阵产生更多的缓存未命中。

答案 3 :(得分:2)

测量它。

优先顺序访问。应该在很大程度上取决于X和Y的值。对于X和Y的某些选择,我预计差异是相当大的。

你应该考虑使用像vector,valarray或boost :: matrix这样的容器。 C风格的数组可能导致可避免和烦人的错误。

答案 4 :(得分:-1)

一个着名的表达:“由于现代计算机的速度,它可能不会产生明显的差异。”