哪个更有效率?重复分配或重复检查

时间:2014-03-10 07:49:27

标签: c performance optimization processing-efficiency

如果我有一个循环来检查数组中的特定值,并且由于某种原因,必须迭代所有元素并且不能中途破坏。

以下哪项更有效:在每场比赛中盲目地设置一个标志,或者在设置之前检查标志是否为假。

bool happened = false;
while (...) {
  if (...) {
    happened = true;
  }
}

VS

bool happened = false;
while (...) {
  if (...) {
    if (!happened) happened = true;
  }
}

据我所知,假设内存读取与内存写入一样快(忽略第二个示例中的额外指令),两者都或多或少相等。我的结论是否正确?

6 个答案:

答案 0 :(得分:4)

如果您使用任何有意义的优化,编译器将为您做出决定。写出最干净,最有意义的东西。对我来说这将是第一个,因为它是更少的代码,并没有引入更多的代码路径。为了好玩,我在Clang 3.4 -O3中做了一些测试:

bool happened = false;
extern volatile int dontOptMe1, dontOptMe2, dontOptMe3;
while (dontOptMe1) {
  if (dontOptMe2) {
    happened = true;
  }
}
dontOptMe3 = happened;

VS

bool happened = false;
extern volatile int dontOptMe1, dontOptMe2, dontOptMe3;
while (dontOptMe1) {
  if (dontOptMe2) {
    if(!happened) happened = true;
  }
}
dontOptMe3 = happened;

在伪ASM中导致以下结果:

  MOV      happened, 0
  BRA      LOOP_END
LOOP_START:
  SELECTEQ dontOptMe2, 0, happened, happened, 1
LOOP_END:
  BCZC     dontOptMe1, LOOP_START
EXIT:
  STORE    dontOptMe3, happened

VS

  MOV      happened, 0
  BCZS     dontOptMe1, EXIT
LOOP:
  SELECTNE dontOptMe2, 0, R2, 1, 0
  SELECTEQ happened, 0, R3, 1, 0
  AND      R3, R2, R3
  SELECTNE R3, 0, happened, 1, 0
  BCZC     dontOptMe1, LOOP
EXIT:
  STORE    dontOptMe3, happened

第一个更令人满意。这也是限制性易失性类型的一个很好的例子。我很惊讶编译器无法将第二个转换为第一个。

注意:SELECTXX表示,如果Arg1减去Arg2设置条件代码XX,则将Arg3设置为Arg4,否则将Arg3设置为Arg5。因此:SELECTNE dontOptMe2, 0, R2, 1, 0相当于:C {/ p>中的R2 = (dontOptMe2 == 0) ? 1 : 0;

答案 1 :(得分:3)

一般来说,第一个版本更加管道友好,因为它的指令流不受跳转的干扰,因此效率更高。但这取决于特定的体系结构功能和编译器优化。

我认为这两个版本的性能差异在实际情况下并不明显。

答案 2 :(得分:1)

到目前为止,大多数答案似乎都是“取决于”,但我认为这很明显: 如果你有条件地将某个值设置为某个东西,如果它不是某个东西,那么它在逻辑上与无条件地设置该值相同。如果你很幸运,编译器会同时注意和处理两者,但如果没有,则无条件版本每次都获胜
1:它使用较少的指令
2:额外的指令是有条件的,损害了分支预测

如果你要去

 if (cond) varx = vary;

编译器使用一个条件分支(如果硬件支持,则可能是条件移动而不是分支)

如果你要去

 if (cond && varx != vary) varx = vary;

编译器将简化为第一种情况,或使用两次条件跳转(或一次跳转和条件移动)。

答案 3 :(得分:0)

只有分析才能确定,但​​最有可能的是变量无论如何都存储在寄存器中,而不是存储在内存中(除非循环中有许多其他局部变量)并且根本没有可测量的差异。

答案 4 :(得分:0)

是的,你说的很对。它们或多或少相同。

确切地说,如果“发生”经常发生,第一种形式可能是可取的,而如果“发生”非常罕见,第二种形式可能希望是有利的。但即便如此,我认为第二种方式不会更好。

最后,它可能是一种微观优化,最好是为了提高可读性而不是性能。

答案 5 :(得分:0)

我已根据以下代码凭经验运行:

bool happened = false;
for (int i = 0; i < 1000000000; i++) {
  if (i % 2) {
    // uncomment the one you want to use
    // happened = true;
    // if (!happened) happened = true;
  }
}

我每次跑了10次,平均值为2.304s,标准差为0.013s,平均值为2.399s,标准差为0.007s。双样本t检验表明happened = true;if (!happened) happened = true;更快,差异具有统计学意义,p = 7e-12。