我们说我有
void f(const bool condition) {
if (condition) {
f2();
else {
f3();
}
f4();
if (condition) {
f5();
} else {
f6();
}
}
因为condition
永远不会改变,所以上面的内容可以简化为以下
void f(const bool condition) {
if (condition) {
f2();
f4();
f5();
} else {
f3();
f4();
f5();
}
}
请注意,f4()
在第二个代码中重复,但第二个代码部分的if
分支较少。我试图描述两个代码片段,但在我看来,性能几乎完全相同。想象一下,在现实生活中,上面的代码片段可以有更多if
条件相同的条件。所以我对现代x86 / 64处理器感到疑惑:
if
语句而不是基于相同条件的许多小语句,是否有任何性能提升? const
关键字帮助编译器/处理器生成更好的分支预测吗? 答案 0 :(得分:2)
首先,要注意任何差异,您需要多次运行您的代码段,例如:
for (int i=0; i<100000000; ++i)
f(true);
您需要选择迭代次数以使总运行时间为10-30秒。在这种情况下,您将看到函数本身的性能,而不是加载应用程序等各种开销。
其次,您的功能f2
...... f6
的复杂程度如何?如果这些函数比f
本身更复杂,那么你也不会发现任何差异。
第三,你的第二个版本会稍快一点,虽然差别很小。添加const
无助于编译器。
最后,我建议您查看可带来显着性能提升的更改。
答案 1 :(得分:2)
首先,您的示例很简单,任何体面的编译器都可以为这两种情况生成identical code。
要足够混淆,你应该做一些更复杂的事情而不是简单地调用f4
,like so:
void f_seprate_ifs(const bool condition) {
if (condition) {
f2();
} else {
f3();
}
for ( int i = 0; i < 100; i++ ){
f4();
}
if (condition) {
f5();
} else {
f6();
}
}
void f_duplicate_f4(const bool condition) {
if (condition) {
f2();
for ( int i = 0; i < 100; i++ ){
f4();
}
f5();
} else {
f3();
for ( int i = 0; i < 100; i++ ){
f4();
}
f6();
}
}
但是这不是风格问题,而是速度和空间之间明确的<强烈“权衡 - 你是重复代码来消除分支(和IMO,它不是一个好的根据我的例子进行权衡)。编译器已经使用函数内联一直这样做,并且在内联时具有非常复杂的启发式。就你的例子而言,它甚至为你做了。
总而言之,除非您完全确定它们是必要的,否则不要尝试进行此类微观优化。特别是当他们伤害可读性时。特别是当它们吸引复制粘贴错误时。
至于const
修饰符,任何体面的编译器都会注意到condition
永远不会改变,并且effectively const,用Java术语说。在C ++中,const
很少提供额外的优化机会。它适用于程序员,而不适用于编译器。
例如,对于:
void f(const bool& condition){
condition
NOT 常量 - 编译器必须假设它可以由f4
更改,因此代码段在语义上不再相同
答案 2 :(得分:0)
理论上,消除任何条件操作都可以提高性能。但在现实世界中,根本没有任何区别。 在您的特定情况下,编译器可以轻松地为您执行建议的优化,因此应该没有区别,因为您已经测试过。优化编译器的一项宝贵工作 - 分支消除。他们寻找避免不必要分支的可能性。
那么,问题1的答案: 在现代编译器的大多数情况下,没有区别。
关于const
关键字:
const
本身对分支预测没有帮助。编译器可以查看是否有任何变量未被修改并应用它们可以生成快速代码。当二进制代码由处理器执行时,没有任何迹象表明该值是常量。至少在x86和x86-64处理器上。
在任何情况下&#34;过早优化是所有邪恶的根源&#34; (c)唐纳德克努特。除非您的分析数据显示瓶颈,否则您需要避免任何低级别优化。为此,您需要一个基准来分析性能。