for-loop机制效率提示

时间:2008-09-28 07:00:22

标签: language-agnostic

由于我在大型多维数组上使用for循环,因此对for循环机制本身的任何保存都是有意义的。

因此,我正在寻找有关如何减少此开销的任何提示。

e.g。 :使用uint而不是int和!= 0倒计时作为stop而不是> 0允许CPU做更少的工作(听过一次,不确定它总是如此)

13 个答案:

答案 0 :(得分:12)

一个重要的建议:尽可能多地计算外循环。并非所有编译器都能自动执行此操作。例如,而不是:

for row = 0 to 999
    for col = 0 to 999
        cell[row*1000+col] = row * 7 + col

使用:

for row = 0 to 999
    x = row * 1000
    y = row * 7
    for col = 0 to 999
        cell[x+col] = y + col

答案 1 :(得分:9)

尝试让你的循环在内存中连续,这将优化缓存使用。也就是说,不要这样做:

for (int i = 0; i < m; i++)  
    for (j = 0; j < n; j++)  
        s += arr[j][i];
  • 如果处理图像,请使用单个索引将两个循环转换为像素上的一个循环。
  • 不要创建将运行零次的循环,因为管道已经过优化,假设循环将继续而不是结束。

答案 2 :(得分:6)

你测量了开销吗?您知道处理for循环花费了多少时间与执行应用程序代码花费了多少时间?你的目标是什么?

答案 3 :(得分:5)

循环展开可以是一种方式。那就是:

for (i=0; i<N; i++) {
  a[i]=...;
}

转换为:

for (i=0; i<N; i+=4) {
  a[i]=...;
  a[i+1]=...;
  a[i+2]=...;
  a[i+3]=...;
}

在上面的示例中,当N不是4的倍数时,您将需要特殊处理。

答案 4 :(得分:4)

这不是一个与语言无关的问题,它不仅高度依赖于语言,还高度依赖于编译器。我相信大多数编译器都会等同地编译这两个:

for (int i = 0; i < 10; i++) { /* ... */ }

int i = 0;
while (i < 10) {
    // ...
    i++;
}

在大多数语言/编译器中,for循环只是后来while循环的语法糖。 Foreach是另一个问题,并且高度依赖于语言/编译器如何实现它,但它通常效率低于普通for / while循环。再多一点,语言和编译器依赖。

你最好的选择可能是在一个主题上运行一些基于几种不同变化的基准测试,看看最重要的是什么。

编辑:为此,suggestions here可能会为您节省更多时间,而不是担心循环本身。

答案 5 :(得分:4)

除非你需要后增量,否则你应该总是使用预增量运算符。这只是一个微小的差异,但效率更高。

在内部,这就是区别:

  • 增量后

    i++;

    与:

    相同

    int postincrement( int &i )
    {
    int itmp = i;
    i = i + 1;
    return itmp;
    }

  • 预增量

    ++i;

    与:

    相同

    int preincrement( int &i )
    {
    i = i + 1;
    return i;
    }

答案 6 :(得分:4)

首先,不要让小东西流汗。计算与倒计时等细节通常与运行时间完全无关。众所周知,人们在寻找需要加速的代码区域方面表现不佳。使用分析器。除非剖析器另有说明,否则很少或不注意循环的任何不重复的部分。请记住,在内循环中编写的内容不一定在内循环中执行,因为现代编译器非常聪明地避免不必要的重复。

话虽如此,要非常警惕在现代CPU上展开循环。它们越紧,它们就越适合缓存。在我去年工作的高性能应用程序中,我通过使用循环而不是直线代码来显着提高性能,并尽可能地加强它们。 (是的,我描述了;有问题的函数占用了80%的运行时间。我还对典型输入的时间进行了基准测试,所以我知道这些变化有帮助。)

此外,开发有利于高效代码的习惯也没有害处。在C ++中,你应该习惯使用预增量(++ i)而不是后增量(i ++)来增加循环变量。它通常没关系,但可以产生显着的差异,它不会使代码不易读取或写入,也不会受到伤害。

答案 7 :(得分:3)

我同意@Greg。您需要做的第一件事是制定一些基准测试。在您证明所有处理时间都花在哪里之前,几乎没有什么可以优化的。 “过早优化是所有邪恶的根源”!

答案 8 :(得分:1)

由于你的循环将具有O(n ^ d)复杂度(d =维度),真正重要的是你把INTO放在循环中,而不是循环本身。在循环框架中优化几个循环,循环内部数百万个低效算法循环只是蛇油。

答案 9 :(得分:1)

顺便说一句,如果保证Int16容量足够,在for循环中使用short代替int是否合适?

答案 10 :(得分:0)

我认为大多数编译器都可能会这样做,降低到零应该更有效,因为对于处理器来说,检查零是非常快的。但是,无论如何,任何值得它重量的编译器都会对大多数循环执行此操作。你需要了解编译器正在做什么。

答案 11 :(得分:0)

没有足够的信息准确回答您的问题。你在循环中做什么?一次迭代中的计算是否取决于先前迭代中计算的值。如果没有,假设你至少拥有一个双核心处理器,你可以通过简单地使用2个线程将时间缩短一半。

另一件需要注意的是,如果您正在进行大型数据处理,您将如何访问数据,以确保按顺序访问数据,因为它存储在内存中,从而避免冲洗您的数据每次迭代都有L1 / L2缓存(在较小的L1缓存之前看到这种情况,差异可能很大)。

同样,我会首先看看循环内部的内容,大多数增益(> 99%),而不是外循环管道。

但话说回来,如果您的循环代码受I / O限制,那么浪费在优化上的任何时间都会浪费。

答案 12 :(得分:0)

另一个stackoverflow问题how cache memory works的答案中有一些相关信息。我发现Ulrich Drepper中提到的this提到的论文特别有用。