<?php
$a = microtime(true);
$num = 0;
for($i=0;$i<10000000;$i++)
{
$num = $i;
}
$b= microtime(true);
echo $b-$a;
?>
我在Ubuntu 12.10和Apache 2上运行它 会给我约。 .50秒......当我执行一百万次任务时......但是......
相同的代码,而不是$num = $i
...我去......
$num = $i + 10;
现在执行的时间减少了近1.5倍..大约.36。
为什么简单的任务需要更多,而分配和在其上添加10 ...需要更少的时间!
答案 0 :(得分:1)
我绝不是专家,但这是我的发现:
$s = microtime(true);
for($i=0;$i<100000000;$i++) $tmp = $i;
$t = microtime(true);
for($i=0;$i<100000000;$i++) $tmp = $i+10;
$u = microtime(true);
echo ($t-$s).chr(10).($u-$t);
结果:
9.9528648853302
9.0821340084076
另一方面,使用常量值进行分配测试:
$x = 0;
$s = microtime(true);
for($i=0;$i<100000000;$i++) $tmp = $x;
$t = microtime(true);
for($i=0;$i<100000000;$i++) $tmp = $x+10;
$u = microtime(true);
echo ($t-$s).chr(10).($u-$t);
结果:
6.1365358829498
9.3231790065765
这让我相信答案与操作码缓存有关。老实说,我无法告诉你它是如何产生差异的,但正如你所看到的,使用一个常量值来进行分配会产生巨大的差异。
答案 1 :(得分:0)
这只是一个有根据的猜测,基于在Github上查看最新的php源代码,但我会说这种差异是由于解释器源中的函数调用开销。
$tmp = $i;
编译为单个操作码ASSIGN !2, !1;
,将一个名为变量的值复制到另一个名为的变量。在源代码中,the key part看起来像这样:
if (EXPECTED(Z_TYPE_P(variable_ptr) <= IS_BOOL)) {
/* nothing to destroy */
ZVAL_COPY_VALUE(variable_ptr, value);
zendi_zval_copy_ctor(*variable_ptr);
}
$tmp = $i + 10;
编译为两个操作码ADD ~8 !1, 10; ASSIGN !2, ~8;
,它创建一个临时变量~8
并将其值赋给名为的变量。在源代码中,the key part看起来像这样:
if (EXPECTED(Z_TYPE_P(variable_ptr) <= IS_BOOL)) {
/* nothing to destroy */
ZVAL_COPY_VALUE(variable_ptr, value);
}
请注意,在第一种情况下,对zendi_zval_copy_ctor()
进行了额外的函数调用。该函数根据需要执行一些簿记(例如,如果原始变量是资源,则需要确保在该新变量消失之前不释放资源,等等)。对于诸如数字之类的原始类型,没有什么可做的,但函数调用本身会引入一些开销,这会累积超过1000万次的测试迭代。你应该注意到这个开销通常可以忽略不计,因为即使在1000万次迭代中它也只累积到.14秒。
@Kolink关于常数更快的观察也可以在同一个函数中回答。如果新值与旧值相同,则为includes a check to avoid redundant copying:
if (EXPECTED(variable_ptr != value)) {
copy_value:
// the same code that handles `$tmp = $i` above
if (EXPECTED(Z_TYPE_P(variable_ptr) <= IS_BOOL)) {
/* nothing to destroy */
ZVAL_COPY_VALUE(variable_ptr, value);
zendi_zval_copy_ctor(*variable_ptr);
} else {
/* irrelevant to the question */
}
}
因此,只有$tmp = $x
的第一个分配才会复制$x
的值,以下内容会看到$tmp
的值不会更改并跳过复制,从而使其更快。< / p>