如果您有以下内容:

$var = 3; // we'll say it's set to 3 for this example
if ($var == 4) {
    // do something
} else if ($var == 5) {
    // do something
} else if ($var == 2) {
    // do something
} else if ($var == 3) {
    // do something
} else {
    // do something
}

如果说80%的时间 $ var 是3,你是否担心在找到真实案例之前它会经历4个案例?

我在一个小网站上思考这不是什么大不了的事,但是当if语句每秒运行1000次时呢?

我在使用PHP,但我认为语言并不重要。

有帮助吗?

解决方案

以下是我在为雷达系统编写软件时的工作方式。 (速度在雷达中很重要。它是少数几个“实时”实际上意味着“真实”而不是“快速”的地方之一。)

[我将切换到Python语法,对我来说更容易,我相信你可以解释它。]

if var <= 3:
    if var == 2:
        # do something
    elif var == 3:
        # do something
    else: 
        raise Exception
else:
    if var == 4:
        # do something
    elif var == 5:
        # do something
    else:
        raise Exception

您的if语句形成树而不是平面列表。当您向此列表添加条件时,您将围绕树的中心进行抖动。 n 比较的平坦序列平均需要 n / 2步。树导致一系列比较,采用log( n )比较。

其他提示

好吧,我相信几乎所有的时间,比如说具有数字排序值的易读性会超越您通过减少比较指令的数量而获得的任何微小收益。

话虽如此,与所有优化一样:

  1. 让它发挥作用
  2. 测量它
  3. 如果它足够快,请不要管它
  4. 如果它太慢,那么优化它
  5. 哦,我可能会从一开始就使用开关/外壳! ; - )

这种情况发生的经典案例(在帖子中有5个选项)在ffmpeg中,在decode_cabac_residual函数中。这非常重要,因为分析(非常重要 - 在分析之前不进行优化!)显示它在H.264视频解码中花费了超过10-15%的时间。 if语句控制了一组语句,这些语句是针对要解码的各种类型的残差而不同地计算的 - 并且不幸的是,如果函数被重复5次,则5种类型的函数中的每一种都会因代码大小而丢失太多的速度。剩余的。因此,必须使用if链。

在许多常见测试流上进行性能分析,以便根据可能性对其进行排序;顶部是最常见的,底部是最少的。这样可以获得很小的速度增益。

现在,在PHP中,我怀疑你在C中获得的低级风格速度增益要少得多,如上例所示。

使用switch / case语句绝对是这里的方法。

这使得编译器(解释器)有机会利用跳转表到达正确的分支而无需进行N次比较。想想它创建一个索引为0,1,2的地址数组,然后它可以在一次操作中在数组中查找正确的地址。

另外,由于case语句中的合成开销较少,因此读起来也更容易。

更新:如果比较适用于switch语句,那么这是配置文件引导优化可以提供帮助的区域。通过运行具有真实测试负载的PGO构建,系统可以生成分支使用信息,然后使用它来优化所采用的路径。

我不会回答PHP问题,而是回答一下。它不直接适用于PHP,因为它会经过某种解释。

许多编译器可以根据需要转换为if-elif-elif -...块来切换块,并且elif-parts中的测试足够简单(其余的语义恰好兼容)。对于3-4次测试,使用跳转表不一定有任何好处。

原因是CPU中的分支预测器非常善于预测发生的情况。实际上,唯一发生的事情是对指令获取的压力要大一些,但它几乎不会让人惊骇。

在您的示例中,大多数编译器会认识到$ var是常量3,然后在if..elif ..块中将$ var替换为3。这反过来使表达式保持不变,因此它们被折叠为true或false。所有假分支都被死代码消除器杀死,并且对于true的测试也被消除。剩下的是$ var == 3的情况。尽管如此,你不能依赖PHP。一般来说,你不能传播$ var,但可能来自某些呼叫站点。

您可以尝试使用一组代码块,您可以调用它们。然后所有代码块都有相同的开销。

Perl 6:

our @code_blocks = (
  { 'Code Block 0' },
  { 'Code Block 1' },
  { 'Code Block 2' },
  { 'Code Block 3' },
  { 'Code Block 4' },
  { 'Code Block 5' },
);

if( 0 <= $var < @code_blocks.length ){
  @code_blocks[$var]->();
}

如果代码必须进行额外的测试,那么它肯定会运行得更慢。如果性能在这部分代码中至关重要,那么您应该首先考虑最常见的情况。

我通常同意“衡量,然后优化”方法,当你不确定性能是否足够快,但如果代码只需要尽可能快地运行并且修复就像重新安排测试一样简单,那么我现在应该快速编写代码并做一些测量在你上线之后确保你的假设(例如那个将在80%的时间内发生)实际上是正确的。

对于代码,它纯粹是一个相等分析,我会将它移动到一个开关/案例,因为它提供了更好的性能。

$var = 3; // we'll say it's set to 3 for this example
switch($var)
 {
   case 4:
      //do something
      break;
   case 5:
      //do something
      break;
   case:
      //do something when none of the provided cases match (same as using an else{ after the elseif{
 }

现在,如果您进行更复杂的比较,我会将它们嵌套在交换机中,或者只使用elseif。

在面向对象语言中,如果一个选项提供了大量ifs,那么这意味着你应该只将行为(例如,你的 //做一些块)移动到包含值的对象。 / p>

只有您可以判断优化订单或重新排列实际上是二叉树的性能差异是否会产生显着差异。但我怀疑你每秒必须有数百万次,而不是数千次,甚至在PHP中思考它(在其他一些语言中更是如此)。

时间。看一下你可以运行上面的if / else if / else语句,没有采取任何行动,$ var不是其中一个选择。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top