4

请考虑以下代码:

$start = microtime();
for($i = 2; $i < 100; $i++)
{
    for($y = 2; $y <= sqrt($i); $y++)
    {
        if($i%$y != 0)
        {
            continue;
        }
        else
        {
          continue 2;
        }
    }

    echo $i.',';
}
echo "\nFinished in " . (microtime() - $start);

鉴于上面的代码有效地使用 continue 2 来中断内部循环并跳过内部循环后的任何代码,为什么下面的代码看起来执行得更多时平均执行得更快:

 $start = microtime();
for($i = 2; $i < 100; $i++)
{
    $flag = true;
    for($y = 2; $y <= sqrt($i); $y++)
    {
        if($i%$y != 0)
        {
            continue;
        }
        else
        {
          $flag = false;
          break;
        }
    }

    if($flag === true) echo $i.',';
}
echo "\nFinished in " . (microtime() - $start);

感谢您的任何意见。

_ _ __更新_ _ __ _ __ _ __ _

感谢您的反馈,但我们似乎错过了重点。不管这是否是一种好的编程实践,我都试图理解为什么性能差异(很小但一致)不在我预期的偏差范围内。

true 到 microtime 的传递似乎无关紧要,因为两个样本都是使用相同的方法测量的,具有相同的开销和相同的不准确性。

正如使用“平均”一词所暗示的那样,测试了不止一次的运行。

只是为了说明,请考虑以下使用 microtime(true) 的小样本,其显示与使用 microtime() 相同的模式。

我知道这是一个小样本,但模式很清楚:

继续 0.00037288665771484 0.00048208236694336 0.00046110153198242 0.00039386749267578 0.0003662109375

断裂 0.00033903121948242 0.00035715103149414 0.00033307075500488 0.00034403800964355 0.00032901763916016

感谢您的关注,并感谢您提供任何进一步的反馈。

_ _ ___ 更新 进一步调查_ _ __ _ __ _ ___

有趣的是,如果从代码中删除了 echo 语句,则 continue 执行得更快,而使用 echo 语句时 break 会更快。

请考虑以下代码示例,并考虑结果是否存在冲突,具体取决于是否删除了 echo 语句:

<?php
$breakStats = array();
$continueStats = array();

ob_start();
for($i = 0; $i < 10000; $i++)
{
   $breakStats[] = doBreakTest();
   $continueStats[] = doContinueTest();
}
ob_clean();

echo "<br/>Continue Mean " . (array_sum($continueStats) / count($continueStats));
echo "<br/>Break Mean " . (array_sum($breakStats) / count($breakStats));

function doBreakTest()
{
    $start = microtime(true);
    for($i = 2; $i < 100; $i++)
    {
        $flag = true;
        $root = sqrt($i);
        for($y = 2; $y <= $root; $y++)
        {
            if($i%$y != 0)
            {
                continue;
            }
            else
            {
                $flag = false;
                break;
            }
        }
    }

    if($flag === true) echo $i . '';
    return microtime(true) - $start;
}

function doContinueTest()
{
    $start = microtime(true);
    for($i = 2; $i < 100; $i++)
    {
        $root = sqrt($i);
        for($y = 2; $y <= $root; $y++)
        {
            if($i%$y != 0)
            {
                continue;
            }
            else
            {
                echo $i . '';
                continue 2;
            }
        }
    }
    return microtime(true) - $start;
}

存在 Echo 语句:

继续平均值 0.00014134283065796 中断平均值 0.00012669243812561

回声语句不存在:

继续平均值 0.00011746988296509 中断平均值 0.00013022310733795

请注意,通过从 break 和 flag 测试中删除 echo 语句,我们还删除了 ($flag === true) 检查,因此负载应该减少,但在这种情况下继续仍然会获胜。W

因此,在纯粹的 continue n 与 break + flag 场景中,似乎 continue n 是更快的构造。但是添加相同数量的相同 echo 语句,以及 continue n 性能标志。

从逻辑上讲, continue n 应该更快,这对我来说是有道理的,但我希望看到存在的 echo 语句相同。

这显然是生成的操作码的差异,并且 echo 语句的位置(内循环与外循环)有人知道查看生成的操作码的方法吗?我想这是我最终需要的,因为我试图了解内部正在发生的事情。

谢谢 :)

4

2 回答 2

2

是的,第一个更快一点。这是因为它只是在 continue 2 上跳出并打印 $i。

第二个例子有更多的工作要做......为$flag变量赋值,跳出循环,检查$flag的值,检查$flag的类型(也比较),然后打印出$i。它有点慢(简单的逻辑)。

无论如何,它有什么目的吗?

我的一些比较结果

0.0011570 < 0.0012173
0.0011540 < 0.0011754
0.0011820 < 0.0012036
0.0011570 < 0.0011693
0.0011970 < 0.0012790

已使用:PHP 5.3.5@ Windows(1000 次尝试;首先 100% 更快)

0.0011570 < 0.0012173
0.0005000 > 0.0003333
0.0005110 > 0.0004159
0.0003900 < 0.0014029
0.0003950 > 0.0003119
0.0003120 > 0.0002370

已使用:PHP 5.3.3@ Linux(1000 次尝试;第一次 32% :第二次更快 68%)

0.0006700 > 0.0004863
0.0003470 > 0.0002591
0.0005360 > 0.0004027
0.0004720 > 0.0004229
0.0005300 > 0.0004366

已使用:PHP 5.2.13@ Linux(1000 次尝试;先 9% :91% 第二更快)

抱歉,我没有更多用于测试的服务器 :) 现在我认为这主要取决于硬件(也可能取决于操作系统)。

一般来说:它只证明Linux服务器比在Windows上运行更快:)

于 2011-04-02T22:07:29.263 回答
2

continue 2版本对我来说稍微快一些。但这些不是您通常需要关心的事情类型。考虑:

for($y = 2; $y <= sqrt($i); $y++)

在这里,您正在计算sqrt每次迭代的。只需将其更改为:

$sqrt = sqrt($i);
for($y = 2; $y <= $sqrt; $y++)

比在两个几乎相同的循环样式之间切换会给您带来更好的改进。

如果您发现它更容易理解,continue 2则应使用。电脑根本不在乎。

要解决有关查看操作码的更新,请参阅:

php -d vld.active=1 -d vld.execute=0 -f foo.php

于 2011-04-02T23:00:10.567 回答