C中的算法比较,有什么区别?

时间:2009-03-29 20:00:56

标签: c algorithm memory-management iteration

#define IMGX 8192
#define IMGY 8192
int red_freq[256];
char img[IMGY][IMGX][3];

main(){ 

int i, j;
  long long total;
  long long redness;

  for (i = 0; i < 256; i++) 
    red_freq[i] = 0;

  for (i = 0; i < IMGY; i++) 
    for (j = 0; j < IMGX; j++) 
      red_freq[img[i][j][0]] += 1;

  total = 0;
  for (i = 0; i < 256; i++) 
    total += (long long)i * (long long)red_freq[i];

  redness = (total + (IMGX*IMGY/2))/(IMGX*IMGY); 

将第二个for循环替换为

时有什么区别
for (j = 0; j < IMGX; j++) 
    for (i = 0; i < IMGY; i++) 
      red_freq[img[i][j][0]] += 1;

其他一切都保持不变,为什么第一种算法比第二种算法更快?

是否与内存分配有关?

6 个答案:

答案 0 :(得分:8)

第一个版本按顺序改变内存,因此最佳地使用处理器缓存。 第二个版本使用它加载的每个缓存行中的一个值,因此它对于缓存使用而言是很小的。

要理解的一点是缓存被划分为多行,每一行都包含整个结构中的许多值。

第一个版本也可能由编译器优化,以使用更快的指令(SIMD指令)。

答案 1 :(得分:5)

这是因为第一个版本按照物理布局的顺序迭代内存,而第二个版本在内存中从数组中的一列跳到下一列。这将导致缓存抖动并干扰CPU的最佳性能,然后必须花费大量时间等待缓存一次又一次地刷新。

答案 2 :(得分:2)

这是因为大型现代处理器架构(如PC中的架构)经过大规模优化,可以处理他们最近访问过的“接近”(与地址相关的术语)内存的内存。实际的物理内存访问比理论上运行的CPU慢得多,所以有助于进程以最有效的方式访问的所有内容都有助于提高性能。

要概括的不仅仅是不可能,但“参考地点”是一个很好的目标。

答案 3 :(得分:1)

由于内存的布局方式,第一个版本维护数据局部性,因此导致缓存未命中次数减少。

答案 4 :(得分:1)

内存分配只发生一次,并且它在开头,所以它不是原因。原因是运行时如何计算地址。在这两种情况下,存储器地址都计算为

(i * (IMGY * IMGX)) + (j * IMGX) + 0

在第一个算法中

(i * (IMGY * IMGX)) gets calculates 8192 times
(j * IMGX) gets calculated 8192 * 8192 times

在第二个算法中

(i * (IMGY * IMGX)) gets calculates 8192 * 8192 times
(j * IMGX) gets calculated 8192 times

(i * (IMGY * IMGX)) 

涉及两次乘法,这样做需要花费更多时间。这就是原因

答案 5 :(得分:0)

是的,它与内存分配有关。第一个循环索引img的内部维度,每次恰好只跨越3个字节。这很容易在一个内存页面内(我相信这里的常见大小为4kB)。但是对于第二个版本,外部维度的索引变化很快。这将导致内存读取扩展到更大范围的内存 - 即sizeof (char[IMGX][3])字节,即24kB。随着内部指数的每次变化,这些跳跃开始再次发生。这将打到不同的页面,可能有点慢。我也听说CPU读取内存。这将使第一个版本受益,因为在它读取时,该数据可能已经在缓存中。我可以想象第二个版本没有从中受益,因为它会使来回内存大量跳跃。

我怀疑差异不是那么大,但如果算法运行多次,它最终会变得明显。您可能想阅读维基百科上的文章Row-major Order。这是用于在C中存储多维数组的方案。