PHP-函数返回赋值性能缓慢


PHP - Slow performance on function return assignment

作为项目的一部分,我遇到了这样的情况:在循环中,我存储函数返回的值。这恰好是应用程序的一个瓶颈,因为处理大型阵列需要很长时间。

对我来说,这项任务不应该成为令人难以置信的缓慢表现的理由。另一方面,相同的函数调用,返回时没有赋值,可以提供更好的性能。

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

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数组返回值不是通过引用传递的,而是通过值传递的。这意味着创建了数组的副本(至少,当您再次更改它时),这反过来又需要时间来实际创建副本(分配内存、memcopy数据)。

这可能与创建10.000个数组有关;每次将数组的元素数量增加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秒

@Jakumi提出了一个很好的观点。由于赋值时必须复制值,因此在第一个循环中需要10000个额外的操作和更多的内存。

两个循环之间的差异实际上比测试显示的要大得多。如果在两次测试之间,你用重置,你的比较会更公平

unset($one); $one = new one();

在当前的测试中,第二个循环正在执行,同时仍将第一个循环中的大数组保存在内存中,因此结果不是独立的。请参阅此修改