8

最速は何ですか?ループの内側または外側のループの外側の変数に基づいて条件を実行する、またはそれが重要であるか(コンパイラーがそれを実行しますか)、または完全に異なる回避策を使用する必要がありますか?

ループ内の条件(単一のforeach)を使用した例1:

$test = 2;  
foreach ($list as $listItem) {
    if ($test == 1) {
        $listItem .= " - one";
    } else if ($test == 2) {
        $listItem .= " - two";
    } else if ($test == 3) {
        $listItem .= " - three";
    }
}

ループの外側の条件を使用した例2(複数のforeachを使用すると非常に醜い):

$test = 2;  
if ($test == 1) {
    foreach ($list as $listItem) {
        $listItem .= " - one";
    }
} else if ($test == 2) {
    foreach ($list as $listItem) {
        $listItem .= " - two";
    }
} else if ($test == 3) {
    foreach ($list as $listItem) {
        $listItem .= " - three";
    }
}
4

2 に答える 2

12

ご想像のとおり、例2の方が高速であり、コンパイラーはそれを行いません。

概要

ループグラフの内側または外側の状態


パフォーマンステスト

例1、ループ内の条件:

Time taken: 0.2501 seconds
Time taken: 0.2336 seconds
Time taken: 0.2335 seconds
Time taken: 0.2319 seconds
Time taken: 0.2337 seconds 
Average:    0.2364 seconds

そしてコード:

<?php
    $list = array();
    for ($i = 0; $i < 1000000; $i++) {
        $list[] = md5(rand(0, 100000) * $i);
    }
    $a = microtime(true);
    $test = 2;
    foreach ($list as $listItem) {
        if ($test == 1) {
            $listItem .= " - one";
        } else if ($test == 2) {
            $listItem .= " - two";
        } else if ($test == 3) {
            $listItem .= " - three";
        }
    }
    echo "Time taken: " . number_format(microtime(true) - $a, 4) . " seconds";
?>

例2、ループ外の条件:

Time taken: 0.1424 seconds
Time taken: 0.1426 seconds
Time taken: 0.1364 seconds
Time taken: 0.1348 seconds
Time taken: 0.1347 seconds
Average:    0.1382 seconds

そしてコード:

<?php
    $list = array();
    for ($i = 0; $i < 1000000; $i++) {
        $list[] = md5(rand(0, 100000) * $i);
    }
    $a = microtime(true);
    $test = 2;
    if ($test == 1) {
        foreach ($list as $listItem) {
            $listItem .= " - one";
        }
    } else if ($test == 2) {
        foreach ($list as $listItem) {
            $listItem .= " - two";
        }
    } else if ($test == 3) {
        foreach ($list as $listItem) {
            $listItem .= " - three";
        }
    }
    echo "Time taken: " . number_format(microtime(true) - $a, 4) . " seconds";
?>

さて、それはループ外の条件のかなり明白な勝利ですが、intではなくブール値と比較しようとするとどうなりますか?

例3、ループ内の条件付け。ただし、代わりにブール値を使用して条件付けします。

Time taken: 0.1845 seconds
Time taken: 0.1821 seconds
Time taken: 0.1745 seconds
Time taken: 0.1777 seconds
Time taken: 0.1767 seconds
Average:    0.1791 seconds

そしてコード:

<?php
    $list = array();
    for ($i = 0; $i < 1000000; $i++) {
        $list[] = md5(rand(0, 100000) * $i);
    }
    $a = microtime(true);
    $test = 2;
    $result1 = ($test == 1);
    $result2 = ($test == 2);
    $result3 = ($test == 3);
    foreach ($list as $listItem) {
        if ($result1) {
            $listItem .= " - one";
        } else if ($result2) {
            $listItem .= " - two";
        } else if ($result3) {
            $listItem .= " - three";
        }
    }
    echo "Time taken: " . number_format(microtime(true) - $a, 4) . " seconds";
?>

面白い。次のような組み込み関数を使用するとどうなりarray_walkますか?

例4 array_walk、:

Time taken: 0.4950 seconds
Time taken: 0.4946 seconds
Time taken: 0.4947 seconds
Time taken: 0.4937 seconds
Time taken: 0.4918 seconds
Average:    0.4940 seconds

そしてコード:

<?php
    function append_string($value, $suffix) {
        return $value . $suffix;
    }

    $list = array();
    for ($i = 0; $i < 1000000; $i++) {
        $list[] = md5(rand(0, 100000) * $i);
    }
    $a = microtime(true);
    $test = 2;
    if ($test == 1) {
        array_walk($list, "append_string", " - one");
    } else if ($test == 2) {
        array_walk($list, "append_string", " - two");
    } else if ($test == 3) {
        array_walk($list, "append_string", " - three");
    }
    echo "Time taken: " . number_format(microtime(true) - $a, 4) . " seconds";
?>

何?! 組み込み関数がCまたはC++関数よりも抽象化すると思うかもしれませんが、それは非常にうまくいくかもしれませんが、問題は、関数呼び出しによってこのメソッドが非常に遅くなることです。


長所短所

例1の長所

  • ループを複数回宣言する必要はありません(複数の条件がある場合は煩わしいかもしれません)

例1の短所

  • これは、最初の3つのテストすべての中で最も遅いテストです(例2より71%遅く、例3より32%遅い)

例2の長所

  • それらすべての中で最も速いもの

例2短所

  • ループを数回宣言する必要があります(条件の数と同じ回数)

例3の長所

  • 例1のように、ループを複数回宣言する必要はありません。
  • #example1よりも高速です

例3短所

  • #example 2よりもまだ遅い(約30%)
  • もっと散らかっているように見える

例4の長所

  • 構文はきれいで簡単に見えます

例4短所

  • これは、ロットの中で最も遅いものです(2番目に遅いもの(例#1)よりも約100%遅い)。おそらく、関数を1,000,000回呼び出さなければならないためです。
  • グローバルスコープから外れているため、グローバルスコープglobalのすべての変数を使用する必要があります。

結論

PHPコンパイラはそれを行いません。パフォーマンスが必要な場合は、たとえば#2に進む必要があります、このテストは、100万のエントリを持つ配列を使用して行われます。配列にはそれほど多くのエントリが含まれない可能性があるため、代わりに例1または例3を使用することをお勧めします。ああ、そして例えば#4には行かないでください

于 2012-09-18T15:40:42.713 に答える
1

条件付きテストの結果がループ中に変更されない場合は、テストをループの外に移動する方が常に高速になります。(一度何かをすることは、同じことを複数回行うよりも明らかに速いです)。

ただし、条件をループの外に移動するときは、それぞれの場合に同じコードを何度も繰り返さないようにします。これがarray_map出番です。例:

function append_str($value, $suffix) {
    return $value . $suffix;
}

if ($test == 1)
    array_map("append_str", $list, " - one");
else if ($test == 2)
    array_map("append_str", $list, " - two");
else if ($test == 3)
    array_map("append_str", $list, " - three");

これにより、条件を1回チェックし、コード再利用して各ケースを処理できます。例に示されているように、各ケースの関数呼び出しをパラメーター化でき、関数(append_str)を必要に応じて複雑にすることができます。

array_map注:ループはおそらくC / C ++で実行されるため、比較のためにこれをベンチマークする価値があります。これは、ネイティブPHPループよりも高速である必要があります(Perlのmap関数と同様)。

于 2012-09-18T15:49:24.077 に答える