版本 A:
if ((A)&&(B)) doSth;
if (B) doSthElse;
版本 B:
if (B)
{
if (A) doSth;
doSthElse;
}
在性能方面,这两者中哪一个更可取?
备注:
实际代码每秒将使用数百万次,因此性能和速度至关重要。在进行分析之前,您能否给我一些意见,以防我遗漏了什么?
代码在 Mac OS X 10.6.8 上使用Clang++
-O3
编译,使用.
版本 A:
if ((A)&&(B)) doSth;
if (B) doSthElse;
版本 B:
if (B)
{
if (A) doSth;
doSthElse;
}
在性能方面,这两者中哪一个更可取?
备注:
实际代码每秒将使用数百万次,因此性能和速度至关重要。在进行分析之前,您能否给我一些意见,以防我遗漏了什么?
代码在 Mac OS X 10.6.8 上使用Clang++-O3
编译,使用.
取决于什么A
和B
是。ifB
是一个复杂的函数,第二个函数只计算一次,而第一个函数计算两次(如果A
成立,当然)。
对于琐碎bool
的情况(即两者),这无关紧要。
而且,当然,您可以进行分析,但我怀疑这将是一个瓶颈。
假设 A 和 B 都是简单的布尔值,我们需要考虑条件解析为的可能性:
快捷评估:如果 (A) 比 (B) 更可能解析为假,则写 (A && B),否则 (B && A)。
分支可预测性:使用更可预测的条件包围大块。例如,如果 B 是可预测的,则首选第二种形式。
尝试将不可预测的条件赋值转换为 (? :),例如,prefer
x = c ? a : b; // data dependency
到
if (c) x = a; // control flow dependency
else x = b;
如果 c 不可预测。在这种情况下,您希望将控制流依赖项替换为数据依赖项,该依赖项可以编译为条件移动。当控制依赖性不可预测时,它是净收益。
如果您的 A 和 B 值是布尔值,那么我会建议第三个版本:
if (A & B) doSth;
if (B) doSthElse;
此版本使用按位 AND 从多个布尔值中创建单个比较。这也可以应用于另一个答案中发布的三元运算符解决方案。
这可能是有益的,因为它会为每个 && 替换删除一个分支。 大多数情况下,将几个布尔值“与”在一起比对每个布尔值进行分支要便宜。这适用于任何具有相对昂贵分支的 cpu 架构,即任何具有乱序执行或长指令执行管道(几乎占所有内容)的东西。
重要提示:在 x86 上,条件执行器和分支预测器足够好,如果布尔 A 预测良好(例如,很少更改且预测率高于 99.6%),那么使用 && 形式和捷径实际上更有效的条件。然而,ARM 和 PowerPC 架构几乎总是受益于更少的分支。