PHP - 函数 return 分配的性能缓慢

PHP - Slow performance on function return assignment

作为项目的一部分,我遇到了这种情况,在循环中,我存储了一个函数的值 return。 这恰好是应用程序的瓶颈,大数组需要永远处理。

对我来说,作业不应该是令人难以置信的缓慢表现的理由。 另一方面,相同的函数调用,在 return 上没有赋值会提供更好的性能。

你能解释一下为什么第一个循环要慢得多吗?

Output: First took 1.750 sec. Second took 0.003 sec.

class one {

    private $var;

    public function __construct() {
         $this->var = array();
    }

    public function saveIteration($a) {     
        $this->var[] = $a;
        return $this->var;
    }

    public function getVar() {      
        return $this->var;      
    }
}

$one = new one();    
$time_start = microtime(true);

for ($i = 0; $i < 10000; $i++) {
    $res = $one->saveIteration($i);
}    
echo "First took " . number_format(microtime(true) - $time_start, 3) . " sec.";

$time_start = microtime(true);

for ($i = 0; $i < 10000; $i++) {
    $one->saveIteration($i);
}  

$res = $one->getVar();
echo "<br>Second took " . number_format(microtime(true) - $time_start, 3) . " sec.";

根据 http://php.net/manual/en/functions.returning-values.php#99660 数组 return 值不是按引用传递,而是按值传递。这意味着创建了数组的副本(至少,当您再次更改它时),这又需要时间来实际创建副本(分配内存,memcopy 数据)。

@Jakumi 说得很对。由于分配时必须复制值,因此在第一个循环中需要 10,000 次额外操作和更多内存。

这两个循环之间的差异实际上比您的测试显示的要大得多。如果在两个测试之间重置为:

,您的比较会更公平
unset($one); $one = new one();

在您当前的测试中,正在执行第二个循环,同时内存中仍保存着第一个循环的大数组,因此您的结果不是独立的。参见 this modification

这可能与您正在创建 10.000 个数组有关;每次将 new 数组的元素数增加 1 个元素。

我的猜测是当您在循环中时,局部变量不会自行释放;因此我继续尝试使用 unset 释放它,结果非常接近。

我知道这不是真实世界的例子;但是在你的代码中,如果你有类似的东西,你可以通过在完成后释放(取消设置)局部变量来摆脱它

这里又是你的测试代码:

class one {

    private $var;

    public function __construct() {
         $this->var = array();
    }

    public function saveIteration($a) {
        $this->var[] = $a;
        return $this->var;
    }

    public function getVar() {
        return $this->var;
    }
}

$one = new one();
$time_start = microtime(true);

for ($i = 0; $i < 10000; $i++) {
    $res = $one->saveIteration($i);
    unset($res);
}
echo "First took " . number_format(microtime(true) - $time_start, 3) . " sec.".PHP_EOL;

$time_start = microtime(true);

for ($i = 0; $i < 10000; $i++) {
    $one->saveIteration($i);
}

$res = $one->getVar();
echo "Second took " . number_format(microtime(true) - $time_start, 3) . " sec.".PHP_EOL;

注意:我唯一修改的是在第一个示例中添加 unset

结果:

  • 第一次用了 0.068 秒
  • 第二个用了 0.062 秒