1
<?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 会给我大约。0.50 秒……当我执行一项任务一百万次时……但是……

相同的代码,而不是$num = $i......我去......

$num = $i + 10;现在执行时间减少了近 1.5 倍……始终保持在 0.36 左右……

为什么简单的作业需要更多时间,而一个作业并在其上加 10... 需要更少的时间!

4

2 回答 2

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

这让我相信答案与操作码缓存有关。老实说,我无法告诉您它有什么不同,但是正如您所看到的,对分配使用常量值会产生巨大的差异。

于 2013-07-28T05:50:05.030 回答
0

这只是一个有根据的猜测,基于查看 Github 上最新的 php 源代码,但我想说这种差异是由于解释器源代码中的函数调用开销造成的。


$tmp = $i;

编译为单个操作码,它将一个命名ASSIGN !2, !1;变量的值复制到另一个命名变量。在源代码中,关键部分如下所示:

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并将其值分配给一个命名变量。在源代码中,关键部分如下所示:

if (EXPECTED(Z_TYPE_P(variable_ptr) <= IS_BOOL)) {
    /* nothing to destroy */
    ZVAL_COPY_VALUE(variable_ptr, value);
}

请注意,zendi_zval_copy_ctor()在第一种情况下有一个额外的函数调用。该函数根据需要执行一些簿记(例如,如果原始变量是资源,它需要确保在这个新变量消失之前不会释放资源,等等)。对于像数字这样的原始类型,没有什么可做的,但函数调用本身会引入一些开销,这会累积超过 1000 万次测试迭代。您应该注意,这种开销通常可以忽略不计,因为即使在 1000 万次迭代中,它也只能累积到 0.14 秒。


@Kolink 关于常数更快的观察也可以在同一函数中得到回答。如果新值与旧值相同,它包括一项检查以避免重复复制:

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不会改变,跳过复制,速度更快。

于 2013-07-28T08:33:22.883 回答