以下哪项更有效?

时间:2010-10-07 20:08:04

标签: c performance

在C:

让我们说函数“Myfuny()”有50行代码,其中也可以调用其他较小的函数。以下哪一个代码更有效?

void myfunction(long *a, long *b);
int i;
for(i=0;i<8;i++)
   myfunction(&a, &b);

myfunction(&a, &b);
myfunction(&a, &b);
myfunction(&a, &b);
myfunction(&a, &b);
myfunction(&a, &b);
myfunction(&a, &b);
myfunction(&a, &b);
myfunction(&a, &b);  

任何帮助将不胜感激。

11 个答案:

答案 0 :(得分:14)

那是不成熟的优化,你应该不在乎......

现在,从代码维护的角度来看,第一种形式(带循环)肯定更好。

从运行时的角度来看,如果函数是内联的并且在同一个编译单元中定义,并且编译器没有展开循环本身,并且代码已经在指令缓存中(我不是知道月相,我仍然相信它不应该有任何显着的效果)第二个可能是最快的。

正如您所看到的,它有很多条件可以让它最快,所以你不应该这样做。在您的程序中可能还有许多其他要优化的参数,这些参数对代码速度的影响要大于此。任何会影响程序算法复杂性的更改都会产生更多更大的影响。更一般地说,任何不影响算法复杂性的代码更改都可能是过早的优化。

如果你真的想确定,衡量。在x86上,您可以使用我在this question中使用的一种技巧来获得相当准确的度量。诀窍是读取计算所花费周期数的处理器寄存器。这个问题还说明了代码优化问题如何变得棘手,即使对于非常简单的问题也是如此。

答案 1 :(得分:4)

我假设编译器会将第一个变体转换为第二个变体。

答案 2 :(得分:3)

第一个。任何有一半体面的编译器都会为你优化。它更容易阅读/理解,更容易编写。

其次,先写,优化第二。即使你的编译器完全是脑死亡和延迟,它最多只能在现代CPU上节省几纳瓦/毫秒的时间。您的应用程序中存在可能/应该首先优化的更大瓶颈。

答案 3 :(得分:2)

这取决于很多事情,你最好的办法是两种方式和措施。

答案 4 :(得分:2)

写出for循环需要更少的时间。我还说用循环阅读更清楚。它可能会保存一些指令来写出来,但是对于现代处理器和编译器,它可能会达到完全相同的结果......

答案 5 :(得分:1)

第一个。它更容易阅读。

答案 6 :(得分:1)

首先,您确定存在代码执行性能问题吗?如果你不这样做,那你就是在谈论让你的代码在没有任何理由的情况下可读性和可写性。

其次,你有没有想过你的程序,看看它是否在一个需要花费大量时间的地方?人类在猜测节目中的热点方面非常糟糕,如果没有剖析,你可能会花费时间和精力来摆弄那些无用的东西。

第三,你要检查生成的汇编代码,看看是否存在差异?如果您正在使用具有优化功能的优化编译器,则可能会生成它认为适合的任何一个。如果您不是,并且遇到性能问题,请购买更好的计算机或启用更多优化。

第四,如果存在差异,您是否要测试两种方式,看哪哪种更好?至少在您的用户将运行的系统的代表性示例中?

而且,为了给你最好的答案,哪个更有效:这取决于你。如果它们实际上被编译为不同的代码,那么展开的版本可能会更快,因为它没有循环开销(包括条件分支),并且汇总版本可能更快,因为它是更短的代码并且可以工作在指令缓存中更好。通常的智慧是展开,但我曾经尽可能紧密地推动执行,加快了一个长期运作的部分。

答案 7 :(得分:0)

在现代处理器上,编译代码的大小变得非常重要。如果这个循环可以从处理器的缓存中顺利运行,那么它将是最快的解决方案。正如n8wrl所说,自己测试一下。

答案 8 :(得分:0)

我为此创建了一个简短的测试,结果令人惊讶。至少对我来说,无论如何,我会认为这是另一回事。

所以,我编写了两个版本的程序迭代函数nothing(),它没有做任何有趣的事情(包含在一个变量上)。

第一个使用了正确的循环(1000次迭代的1000次迭代,两次嵌套的fors),第二次使用了1000次连续的无调用()的迭代。

我用时间命令来衡量。具有适当循环的版本平均花费大约3.5秒,并且连续调用版本平均花费大约2.5秒。

然后我尝试使用优化标志进行编译,但是gcc检测到程序基本上什么也没做,并且两个版本的执行都是瞬时的。没有打扰那个。

编辑:如果您实际上想在代码中连续编写8个调用,请不要。请记住这句名言:“必须编写程序供人们阅读,并且只能偶然为机器执行。”

另请注意,我的测试除了没有()(= P)之外什么也没做,并且在任何实际程序中都没有适当的基准。

答案 9 :(得分:0)

循环展开可以使执行更快(否则Duff的设备不会被发明),但这是许多变量的函数(处理器,缓存大小,编译器设置,{{1}实际上是在做等等,你不能依赖它永远是真的,或者无论如何改进都值得在可读性和可维护性方面付出代价。唯一可以确定是否对您的特定平台产生影响的方法是对两个版本进行编码并对其进行分析。

取决于myfunction实际上做了什么,差异可能在噪音中如此之远,以至于无法察觉。

只有满足以下所有条件时才能进行这种微优化:

  1. 您未能满足严格的性能要求;
  2. 您已经为手头的问题选择了合适的算法和数据结构(例如,在一般情况下,优化不佳的Quicksort将从高度优化的冒泡排序中击败裤子,在最坏的情况下,他们会同样糟糕);
  3. 您正在使用编译器提供的最高级别的优化进行编译;

答案 10 :(得分:0)

myFunction(long *a, long *b)做了多少?

如果它比*a = *b + 1;做得多,那么调用函数的成本与函数内部的成本相比可能非常小,而实际上你正专注于错误的位置。

另一方面,在应用程序的整体情况中,这8个调用花费了多少时间?如果它不是很多,那么无论你如何紧密地优化它都不会产生太大的影响。

正如其他人所说,个人资料,但这并不像听起来那么简单。这是the method I and some others use