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 秒
作为项目的一部分,我遇到了这种情况,在循环中,我存储了一个函数的值 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 秒