开发者

PHP why is continue n slower than using break

开发者 https://www.devze.com 2023-02-21 09:49 出处:网络
Please consider the following code: $start = microtime(); for($i = 2; $i < 100; $i++) { for($y = 2; $y <= sqrt($i); $y++)

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 t开发者_高级运维hat 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 :)


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 :)


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:

  • http://pecl.php.net/package/vld

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

0

精彩评论

暂无评论...
验证码 换一张
取 消