php - 为什么不必要的 IF 子句会提高性能?

标签 php performance is-empty

我有一个简单的方法:

public function validateStringByPrefix(string $string, $prefix)
{
    $valid = false;
    if (is_string($prefix)) {
        if (! empty($prefix) && strpos($string, $prefix) === 0) {
            $valid = true;
        }
    } elseif (is_array($prefix)) {
        foreach ($prefix as $partPrefix) {
            if (! empty($partPrefix) && strpos($string, $partPrefix) === 0) {
                $valid = true;
                break;
            }
        }
    }
    return $valid;
}

我注意到后,条件 ! empty($prefix) 其实是不需要的,我把它去掉了。我预计性能会有最小的提高,或者至少与更改之前的性能相同。但相反,性能却变得更差。

只有在实际存在 $prefix$partPrefix 的情况下,它才有意义。因为 empty(...) 检查非常便宜。

但没有这样的情况,我检查过:

if(empty($prefix)) {
    die(__FILE__);
}

之前:Webgrind(百分比),使用 if(!empty(...))

before (with if(! empty(...)))

之后:Webgrind(百分比),没有 if(!empty(...))

after (without if(! empty(...)))

那么什么可以解释这种行为呢?为什么总是失败的不必要的 IF 子句会提高性能?


更新

刚刚以毫秒为单位查看了 Webgrind 报告:

之前:Webgrind(以毫秒为单位),使用 if(!empty(...))

before (in milliseconds, with if(! empty(...)))

之后:Webgrind(以毫秒为单位),没有 if(!empty(...))

after (in milliseconds, without if(! empty(...)))

因此,以毫秒为单位计算,删除不必要的 IF 子句会提高性能...以百分比为单位的结果与以毫秒为单位的结果有何不同?

最佳答案

事实上,有一个完全合乎逻辑的原因可以证明一个函数比另一个函数稍微快一点,并且与您删除或添加 empty() 条件的事实无关。

这些差异很小,必须以微秒为单位进行测量,但实际上存在差异。区别在于函数的调用顺序,或者更具体地说,它们在 PHP VM 堆中的分配位置。

您在这里遇到的性能差异实际上可能因系统而异。因此,不应期望得到相同的结果。然而,基于有限的系统规范存在一些期望。由此,我们实际上可以重现一致的结果,以证明为什么两个函数之间只有几微秒的差异。

首先看一下this 3v4l我们将带有和不带有 empty() 条件的函数分别定义为 validateStringByPrefix1()validateStringByPrefix2()。在这里,我们首先调用 validateStringByPrefix2(),这会导致执行时间看起来40 微秒。请注意,在这两种情况下,函数都应返回 false,并且 empty($prefix) 永远不会为 true(就像您在自己的测试中所做的那样)。在使用使用empty($prefix)的第二个测试中,看起来该函数实际上执行得更快,11微秒

其次,看一下this 3v4l我们定义了完全相同的函数,但调用 validateStringByPrefix1() first,并得到相反的结果。现在看起来使用empty($prefix)该函数在12微秒运行稍快,而另一个在运行稍慢>88 微秒

请记住,microtime() 实际上并不是一个准确的时钟。它可以在几微秒内轻微波动,但通常不足以平均慢或快一个数量级。所以,是的,存在差异,但是这并不是因为使用empty()或缺少它。

相反,这个问题与典型的 x86 架构如何工作以及 CPU 和内存如何处理缓存有更多关系。代码中定义的函数通常由 PHP 按照首次执行的顺序存储到内存中(此处发生编译步骤)。第一个执行的函数将首先被缓存。存在直写式缓存的概念,例如,可以实现此目的的写分配无写分配。下一个要执行的函数会覆盖该缓存,从而导致内存稍微减慢,这可能会或可能不一致,具体取决于我不会在这里讨论的因素。

但是,尽管存在所有这些微小的差异,尽管在此代码中使用或删除了 empty(),但实际上并没有更快或更慢的结果。这些差异只是每个程序都会遭受的内存访问和分配权衡。

这就是为什么当您确实需要对程序代码进行微优化以尽可能快地执行时,您通常会经历 Profile-guided Optimization 的艰苦过程。或PGO

Optimization techniques based on analysis of the source code alone are based on general ideas as to possible improvements, often applied without much worry over whether or not the code section was going to be executed frequently though also recognising that code within looping statements is worth extra attention.

关于php - 为什么不必要的 IF 子句会提高性能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39510966/

相关文章:

python-3.x - 如何根据该模型上的权重字段快速获取 Django 模型实例的加权随机实例?

javascript - 如何确定 Javascript 数组中的字段为空还是 null?

memory - Go - 初始化一个空 slice

php - 让Azure Web应用程序显示php错误

php - 使用 CakePHP 存储 SQL 数据以供离线使用

python - 用 Pandas 循环遍历数据帧的最有效方法是什么?

java应用程序在netbeans之外运行得更快

ios - 如果没有在 Swift 中的 TextField 中输入文本,则使 UIButton 处于非事件状态

php - 如何允许一些特殊字符以及如何使用 PHP pdo 将它们插入 MySQL

php - 根据外键编辑计划