PHP 为什么 continue 比使用 break 慢

发布于 2024-10-30 02:11:58 字数 3620 浏览 3 评论 0原文

请考虑以下代码:

$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);

感谢您的任何输入。

_____更新< /em>____________

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

真实时间到微时间的传递似乎微不足道,因为两个样本都是使用相同的方法、相同的开销和相同的不准确度进行测量的。

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

仅出于说明目的,请考虑以下使用 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 语句:

Continue Mean 0.00014134283065796 Break Mean 0.00012669243812561

Echo 语句不存在:

Continue Mean 0.00011746988296509 Break Mean 0.00013022310733795

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

,在纯粹的 continue n 与 break + flag 场景中,看起来 continue n 是更快的结构。但添加相同数量的相同 echo 语句以及 continue n 性能标志。

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

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

谢谢 :)

Please consider the following code:

$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);

Given that the above code effectively uses continue 2 to break the inner loop and skip any code post the inner loop, why does the following code on average execute faster when it appears to do more:

 $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);

Thanks for any input.

_____ Update ____________

Thanks for the feedback but we seem to have missed the point. Regardless of if this is good programming practice I was trying to understand why the performance difference (which is tiny but consistent) is not within the bias I expected.

The passing of true to microtime seems insignificant as both samples are measured using the same method with the same overhead and the same inaccuracy.

More than one run was tested, as implied by use of the word average.

Just for illustration please consider the following small samples using microtime(true) which shows the same pattern as using microtime().

I know this is a small sample but the pattern is quite clear:

Continue
0.00037288665771484
0.00048208236694336
0.00046110153198242
0.00039386749267578
0.0003662109375

Break
0.00033903121948242
0.00035715103149414
0.00033307075500488
0.00034403800964355
0.00032901763916016

Thanks for looking, and thanks for any further feedback.

______ UPDATE Further investigation ____________

Interestingly if the echo statements are removed from the code the continue performs faster, with the echo statements in place break is faster.

Please consider the following code sample, and consider that the results are in conflict dependant on if the echo statements are removed or not:

<?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 statements present :

Continue Mean 0.00014134283065796
Break Mean 0.00012669243812561

Echo statements not present :

Continue Mean 0.00011746988296509
Break Mean 0.00013022310733795

Note that by removing the echo statement from the break and flag test we also remove the ($flag === true) check, so the load should reduce, but continue in this case still wins. W

So in a pure continue n versus break + flag scenario, it appears that continue n is the faster contstruct. But add an equal number of identical echo statements, and the continue n performance flags.

This makes sense to me logically that continue n should be faster, but I would have expected to see the same with the echo statements present.

This is clearly a difference in the generated opcodes, and the position of the echo statement (inner loop vs outer loop) does anyone know a way of seeing the opcodes generated? This I suppose is ultimatley what I need as I am trying to understand what is happening internally.

Thanks :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

策马西风 2024-11-06 02:11:58

是的,第一个有点快。这是因为它只是在 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 次尝试;第一次 68% 更快) 9% 第一:91% 第二更快)

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

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

Yes, first one is bit faster. It's because it just jumps out on continue 2 and prints $i.

2nd example has more job to do... assign value to $flag variable, jumps out of loop, checks $flag's value, checks $flag's type (compares too) and then prints out $i. It's bit slower (simple logic).

Anyways, has it any purpose?

Some of my results for comparing

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

Used: PHP 5.3.5 @ Windows (1000 attempts; 100% first was faster)

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

Used: PHP 5.3.3 @ Linux (1000 attempts; 32% first : 68% second was faster)

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

Used: PHP 5.2.13 @ Linux (1000 attempts; 9% first : 91% second was faster)

Sorry, I don't have any more servers for testing :) Now I think it mostly depends of hardware (and maybe depends of OS too).

Generally: It proves only that Linux server is faster than one run at Windows :)

梦里°也失望 2024-11-06 02:11:58

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

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

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

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

将会比在两个几乎相同的循环样式之间切换提供更好的改进。

如果您发现更容易理解,则应使用继续2。电脑根本不关心。

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

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

The continue 2 version is slightly faster for me. But these aren't the types of things you generally need to concern yourself with. Consider:

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

Here you are calculating the sqrt on every iteration. Just changing that to:

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

will give you a much better improvement than switching between two nearly identical loop styles.

The continue 2 should be used if you find that it's easier for you to understand. The computer doesn't really care.

To address your update regarding looking at opcodes, see:

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文