更深入地理解循环(for,while,do while,foreach,recursion等)

rob*_*nal 2 performance loops memory-management

如果给你一些情况,你可以做一个需要使用循环解决的特定事件或函数的循环,你可以通过任何类型的循环来实现这些.我们如何根据速度,效率和内存使用情况确定可以使用的每个循环之间的区别?例如,你有这些循环

for(int i=0;i<10;i++) {
    array[i] = i+1;
}

int i = 0;
while(i<10) {
    array[i] = i+1;
    i++;
}
Run Code Online (Sandbox Code Playgroud)

上面的例子有相同的输出,当然你在执行时看不到它们之间的区别,因为这只是一个小过程,如果你正在处理一个耗费你记忆的巨大循环怎么办?哪个循环更好用?是否有适当的措施何时使用什么循环?

编辑:

对于pakore的回答,

从你的答案我可以有把握地说,如果我重新排序我的变量,其中大多数依赖的变量彼此相距很远(其他行在其中)可能更有效.比如说,

a=0;
b=1;
c=5;
d=1;
for(int i=0; i<10;i++)
{
    a=b*CalculateAge()+d;
    m=c+GetAvarage(a);
    d++;
}
Run Code Online (Sandbox Code Playgroud)

a=0;
b=1;
c=5;
d=1;
for(int i=0; i<10;i++)
{
    a=b*CalculateAge()+d;
    d++;
    m=c+GetAvarage(a);
}
Run Code Online (Sandbox Code Playgroud)

后者比第一行效率更高,因为后者我在第一行调用了外部方法,第二行独立于第一行的结果而不是第三行的结果.

由于第一个示例将在执行第二行之前等待第一行的结果并且在第三行之后等待第二行的结果,并且第二个示例在等待第一行的结果时已经执行了第二行.

结论:

优化的循环不会影响您正在使用的循环类型.正如pakore所解释的那样,以及polygenelubricants,你在循环中可以想到的主要问题是你的代码是如何编写的.编译器的工作是优化代码,如果你根据每个变量的依赖性优化你的代码,它也会有所帮助,正如下面的pakore所解释的那样.

pak*_*ore 8

好吧,这里很难解释循环背后的所有逻辑.

为了优化循环,编译器会为你做一些惊人的事情,所以无论你是使用while还是for因为编译器都会转换为汇编程序并不重要.

为了更深入地理解,您应该学习一些汇编程序,然后学习基本处理器的工作原理,它如何读取指令以及如何处理它们.

为了改进流水线操作,最好将具有相同变量的语句放在彼此远离的位置.这样,当计算一个语句时,处理器可以采用下一个语句,如果它独立于第一个语句并开始计算它.

例如:

a=0;
b=3;
c=5;
m=8;
i=0;
while(i<10){
a=a+b*c;
b=b*10+a;
m=m*5;
i++;
}
Run Code Online (Sandbox Code Playgroud)

我们之间有一个依赖关系a,b而且这些语句是紧挨着的.但是我们看到mi独立于其他人,所以我们可以这样做:

a=0;
b=3;
c=5;
m=8;
i=0;
while(i<10){
a=a+b*c;
m=m*5;
i++;
b=b*10+a;

}
Run Code Online (Sandbox Code Playgroud)

因此,a在计算时,我们可以开始计算mi.大多数情况下,编译器会检测到并自动执行此操作(它是调用代码重新排序).有时候对于小循环,编译器会根据需要多次复制和粘贴循环中的代码,因为没有控制变量会更快.

我的建议是让编译器关注这些事情并关注你正在使用的算法的成本,最好从O(n!)减少到O(logn),而不是在循环内进行微优化.

根据修改的问题更新

好吧,依赖关系必须是写/写或读/写依赖.如果它的读/读依赖性没有问题(因为值不会改变).查看[数据依赖性文章](http://en.wikipedia.org/wiki/Data_dependency).

在您的示例中,两个代码之间没有区别,m取决于c并且b但是这两个代码从未被写入,因此编译器在进入循环之前知道它们的值.这称为读/读依赖,它本身不是依赖.

如果你写了:

...
m=c+GetAvarage(a);
...
Run Code Online (Sandbox Code Playgroud)

然后我们将有一个写/读依赖(我们必须写入a然后读取a,所以我们必须等到a计算),你做的优化会很好.

但是再次,编译器会为您和许多其他事情做这件事.很难说高级代码中的微优化会对汇编程序代码产生真正的影响,因为编译器可能已经为您做了这样的事情,或者可能正在为您重新排序代码,或者可能正在执行其他一千件事情比我们乍一看还要好.

但无论如何,知道如何在地毯下工作是件好事:)

更新以添加一些链接 查看这些链接以进一步了解编译器可以做些什么来提高代码性能:

循环展开

依赖性分析

自动并行化

矢量