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() を使用した場合と同じパターンを示す microtime(true) を使用した次の小さなサンプルを検討してください。

これは小さなサンプルですが、パターンは非常に明確です。

続ける

ブレーク 0.00033903121948242 0.00035715103149414 0.00033307075500488 0.00034403800964355 0.00032901763916016

ご覧いただきありがとうございます。さらにフィードバックをお寄せいただきありがとうございます。

__ _ ___ 更新 さらなる調査__ _ __ _ _ _ __

興味深いことに、コードから echo ステートメントを削除すると、continue の実行が速くなり、echo ステートメントを配置すると、break の実行が速くなります。

次のコード サンプルを検討してください。エコー ステートメントが削除されたかどうかによって、結果が競合することを考慮してください。

<?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;
}

エコーステートメントが存在します:

続行 平均 0.00014134283065796 中断 平均 0.00012669243812561

エコー ステートメントが存在しません:

続行 平均 0.00011746988296509 中断 平均 0.00013022310733795

ブレークとフラグのテストから echo ステートメントを削除することで、($flag === true) チェックも削除することに注意してください。そのため、負荷は軽減されますが、この場合は継続が優先されます。W

そのため、純粋な continue n 対 break + flag のシナリオでは、continue n の方が高速な構造のように見えます。ただし、同数の同一の echo ステートメントと、continue n パフォーマンス フラグを追加します。

これは、論理的には continue n の方が高速であることは理にかなっていますが、存在する echo ステートメントでも同じことが予想されます。

これは明らかに生成されたオペコードの違いであり、エコー ステートメントの位置 (内側のループと外側のループ) は、生成されたオペコードを確認する方法を知っていますか? これは、内部で何が起こっているのかを理解しようとしているときに必要なものだと思います。

ありがとう :)

4

2 に答える 2

2

バージョンはcontinue 2私にとって少し速いです。しかし、これらはあなたが一般的にあなた自身に関係する必要があるタイプのものではありません。検討:

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

sqrtここでは、すべての反復でを計算しています。これを次のように変更するだけです。

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

2つのほぼ同一のループスタイルを切り替えるよりもはるかに優れた改善が得られます。

continue 2理解しやすいと思われる場合は、を使用する必要があります。コンピュータは本当に気にしません。

オペコードの確認に関する最新情報に対処するには、以下を参照してください。

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

于 2011-04-02T23:00:10.567 に答える
2

はい、最初のものは少し速いです。これは、continue 2 で飛び出して $i を出力するためです。

2 番目の例には、やるべきことがもっとあります... $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% : 2 番目の 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% : 2 番目の 91% が速かった)

申し訳ありませんが、テスト用のサーバーはこれ以上ありません:)今、それは主にハードウェアに依存していると思います(おそらくOSにも依存しています)。

一般的に:LinuxサーバーがWindowsでの実行よりも高速であることを証明するだけです:)

于 2011-04-02T22:07:29.263 に答える