<?php
$array = array();
for($i=0; $i<100000; $i++) {
$array[] = mt_rand();
}
function recursiveCopy($array, $count) {
if($count === 1000)
return;
$foo = $array;
recursiveCopy($array, $count+1);
}
function recursiveReference($array, $count) {
if($count === 1000)
return;
$foo = &$array;
recursiveReference($array, $count+1);
}
$time = microtime(1);
recursiveCopy($array, 0);
$copyTime = (microtime(1) - $time);
echo "Took " . $copyTime . "s \n";
$time = microtime(1);
recursiveReference($array, 0);
$referenceTime = (microtime(1) - $time);
echo "Took " . $referenceTime . "s \n";
echo "Reference / Copy: " . ($referenceTime / $copyTime);
我得到的实际结果是,recursiveReference只需20次(!),只要recursiveCopy。
有人可以解释一下这种PHP行为吗?
答案 0 :(得分:17)
PHP很可能会为其数组实现copy-on-write,这意味着当您“复制”数组时,PHP不会完成物理复制内存的所有工作,直到您修改其中一个副本并且您的变量可以不再引用相同的内部表示。
因此,您的基准测试存在根本缺陷,因为您的recursiveCopy
函数实际上并未复制对象;如果确实如此,你会很快耗尽内存。
试试这个:通过分配数组元素,你可以强制PHP 实际制作副本。你会发现你的内存耗尽很快,因为没有任何副本超出范围(并且不会被垃圾回收),直到递归函数达到其最大深度。
function recursiveCopy($array, $count) {
if($count === 1000)
return;
$foo = $array;
$foo[9492] = 3; // Force PHP to copy the array
recursiveCopy($array, $count+1);
}
答案 1 :(得分:3)
在recursiveReference中你正在调用recursiveCopy ...这没有任何意义,在这种情况下你只需要调用recursiveReference一次。纠正你的代码,再次使用基准并返回你的新结果。
此外,我不认为基准测试以递归方式执行此操作是有用的。一个更好的解决方案是在一个循环中调用一个函数1000次 - 一次是直接使用数组,另一次是对该数组的引用。
答案 2 :(得分:3)
出于性能原因,您不需要(因此不应该)通过引用分配或传递变量。 PHP会自动执行此类优化。
由于这些自动优化,您运行的测试存在缺陷。在运行以下测试:
<?php
for($i=0; $i<100000; $i++) {
$array[] = mt_rand();
}
$time = microtime(1);
for($i=0; $i<1000; $i++) {
$copy = $array;
unset($copy);
}
$duration = microtime(1) - $time;
echo "Normal Assignment and don't write: $duration<br />\n";
$time = microtime(1);
for($i=0; $i<1000; $i++) {
$copy =& $array;
unset($copy);
}
$duration = microtime(1) - $time;
echo "Assignment by Reference and don't write: $duration<br />\n";
$time = microtime(1);
for($i=0; $i<1000; $i++) {
$copy = $array;
$copy[0] = 0;
unset($copy);
}
$duration = microtime(1) - $time;
echo "Normal Assignment and write: $duration<br />\n";
$time = microtime(1);
for($i=0; $i<1000; $i++) {
$copy =& $array;
$copy[0] = 0;
unset($copy);
}
$duration = microtime(1) - $time;
echo "Assignment by Reference and write: $duration<br />\n";
?>
这是输出:
//Normal Assignment without write: 0.00023698806762695
//Assignment by Reference without write: 0.00023508071899414
//Normal Assignment with write: 21.302103042603
//Assignment by Reference with write: 0.00030708312988281
正如您所看到的那样,在您实际写入副本之前,通过引用进行分配没有明显的性能差异,即当存在功能差异时。
答案 3 :(得分:1)
一般来说,在PHP中,出于性能原因,您不能通过引用进行调用;这是你出于功能原因所做的事情 - 也就是因为你真的希望更新引用的变量。
如果您没有通过引用调用的功能原因,那么您应该坚持使用常规参数传递,因为PHP以这种方式完美地处理事物。
(正如其他人所指出的那样,你的示例代码并不完全符合你的想法;)
答案 4 :(得分:0)
答案 5 :(得分:0)
recursiveReference正在调用recursiveCopy。 这并不一定会损害性能,但这可能不是你想要做的。
不确定为什么性能较慢,但它并不反映您尝试进行的测量。