在这种情况下,是否有更快的替代if-else?

时间:2011-01-13 15:41:49

标签: c++ c performance

while(some_condition){  
    if(FIRST)  
    {   
        do_this;  
    }  
    else  
    {  
        do_that;  
    }
}

在我的程序中if(FIRST)成功的可能性大约是10000中的1。在C / C ++中是否可以有任何替代方法,以便我们可以避免在while循环内的每次迭代中检查条件,希望看到在这种情况下表现更好。

确定!让我详细介绍一下。 我正在编写一个信号采集和跟踪方案的代码,我的系统状态将更频繁地保持在跟踪模式的ACQUISITION模式。

while(signal_present)  
{    
    if(ACQUISITION_SUCCEEDED)  
    {     
        do_tracking();  // this functions can change the state from TRACKING to ACQUISITION  
    }    
    else  
    {    
        do_acquisition();  // this function can change the state from ACQUISITION to TRACKING  
    }     
}    

所以这里发生的是系统通常保持跟踪模式,但是当跟踪失败时它可以进入采集模式但不常见。(假设输入数据的数量是无限的。)

10 个答案:

答案 0 :(得分:11)

单个分支的性能成本不会是一个大问题。你唯一能做的就是把最可能的代码放在第一位,保存在一些指令缓存上。也许。这非常深入到微观优化中。

答案 1 :(得分:7)

尝试优化此功能没有特别好的理由。几乎所有现代架构都包含branch predictors。这些推测分支(if或者其他)将基本上采用过去的方式。在您的情况下,推测将始终成功,消除所有开销。有一些不可移植的方法可以暗示条件是以这种或那种方式采取的,但任何分支预测器都可以正常工作。

您可能希望改进指令缓存局部性的一件事是将do_that移出while循环(除非是函数调用)。

答案 2 :(得分:3)

在最近的x86处理器系统上,最终执行速度几乎不依赖于源代码实现。

您可以查看此页面http://igoro.com/archive/fast-and-slow-if-statements-branch-prediction-in-modern-processors/,了解处理器内部的优化情况。

答案 3 :(得分:3)

GCC有一个__builtin_expect“函数”,可用于向编译器指示可能采用的分支。您可以像这样使用它:

if(__builtin_expect(FIRST, 1)) …

这有用吗?我不知道。我从未使用它,从未见过它(据称在Linux内核中除外)。 GCC文档实际上不鼓励使用它来支持使用分析信息来实现更可靠的度量标准。

答案 4 :(得分:0)

如果您不知道何时“FIRST”为真,那么不。

问题在于FIRST是否耗时;也许你可以在循环之前评估FIRST(或者它的一部分),然后测试布尔值。

答案 5 :(得分:0)

我将moonshadow的代码改为

while( some_condition )
{
   do_that;
   if( FIRST )
   {
     do_this; // overwrite what you did earlier.
   }
}

答案 6 :(得分:0)

根据您的新信息,我会说以下内容:

while(some_condition)
{
  while(ACQUISITION_SUCCEEDED)
  {
    do_tracking();
  }
  if (some_condition)
    while(!ACQUISITION_SUCCEEDED)
    {
      do_acquisition();
    }
}

关键是ACQUISITION_SUCCEEDED状态必须在某种程度上包含some_condition信息(即如果some_condition为假,它将突破内部循环 - 因此有一个有机会突破外圈)

答案 7 :(得分:0)

这是优化中的经典之作。如果可以的话,你应该避免将条件放在循环中。这段代码:

while(...)
{
    if( a )
    {
       foo();
    }
    else
    {
       bar();
    }
}

通常更好地重写为:

if( a )
{
    while(...)
    {
        foo();
    }
}
else
{
    while(...)
    {
        bar();
    }
}

虽然并不总是可行的,但是当你尝试优化某些东西来测量前后的性能时,你应该总是这样。

答案 8 :(得分:0)

如果与do_aquisition的实现相比,此测试确实耗费了大量时间,那么您可以通过使用函数表来获得提升:

typedef void (*trackfunc)(void);
trackfunc tracking_action[] = {do_acquisition, do_tracking};
while (signal_present)
{
   tracking_action[ACQUISITION_STATE]();
}

这些手动优化的效果非常依赖于平台,编译器和优化设置。

通过花时间测量和调整do_aquisition和do_tracking算法,您很可能获得更大的性能提升。

答案 9 :(得分:0)

您可以对示例进行更多有用的优化。

do_thisdo_that的通话/分支可能会通过优化if-then-else语句来抵消您获得的任何节省。

性能优化的一个规则是减少分支。大多数处理器更喜欢执行顺序代码。他们可以获取一大块顺序代码并将其拖入缓存中。分支中断了这种愉悦,并可能导致指令缓存的完全重新加载(这会浪费宝贵的执行时间)。

在此级别进行微量优化之前,请检查您的设计,看看是否可以:

  1. 消除不必要的分支。
  2. 拆分代码,使其适合 高速缓存中。
  3. 整理数据以减少提取 从内存或硬盘驱动器。
  4. 我确信上述步骤可以获得比优化发布循环更多的性能。