特に目新しい要素はありません。
Q
低回数のfor
ループでも最適化したほうがいい?
A
何回でも最適化したほうがいい。
大体1.5~2倍早くなる…かも。
概要
forの最適化は公式にものっていますが、巷の速度検証はパッと見
-
for
,foreach
,while
の比較 - 10000回以上のループ時の最適化結果
などがよく出てきます。
でも、実際使うループって、ちっさい奴の方が多くて、多くて数十回。
条件によるが、1,2回が多いよーってループもあります。
そんなループが毎回count
しているとして、それを最適化するべきか。
- 改善したとして、2,3回のループでは誤差の範囲なのでは?
- 変数を増やすことで、低回数では逆転現象が起きるのでは?
という、9割方ありえないと言える疑問が出たので解消しておきます。
コード
<?php
function benchmark($name, $repeat, $action)
{
$sumNormal = 0.0;
$sumBetter = 0.0;
for ($i = 0; $i <= $repeat; ++$i) {
list($normal, $better) = $action($name);
$sumNormal += $normal;
$sumBetter += $better;
}
echo "[$name]\n";
printf("Repeat: %d\n", $repeat);
printf("SumNormal: %.6f\n", $sumNormal);
printf("SumBetter: %.6f\n", $sumBetter);
printf("AverageNormal: %.12f\n", $sumNormal / $repeat);
printf("AverageBetter: %.12f\n", $sumBetter / $repeat);
}
function loop($repeat)
{
$array = range(1, $repeat);
$start = microtime(true);
for ($i = 0, $tmp = array(); $i < count($array); ++$i) {
$tmp[] = $array[$i];
}
$end = microtime(true);
$normal = $end - $start;
$start = microtime(true);
for ($i = 0, $tmp = array(), $arrayCount = count($array); $i < $arrayCount; ++$i) {
$tmp[] = $array[$i];
}
$end = microtime(true);
$better = $end - $start;
return array($normal, $better);
}
for ($i = 1; $i <= 20; ++$i) {
benchmark($i, 1000, function ($i) {
return loop($i);
});
}
別記事で頂いたコメントのコードが使いやすそうだったので少しお借りしましたが、その他が微妙…
一応、1~20回のループの実行時間を、最適化前後で取ることを目的としたコードです。
for
内は何でも良かった。
関係無いこと
コールバックとクロージャーを使いこなせていませんでした。
callback $action
に関数の結果やクロージャーを渡しまくって怒られたので、
結局タイプヒンティングを外すことに…
クロージャーへのループ回数も$name
使っちゃったりで要調べ直しですわ…
結果
1000回の平均値です。
回数 | 最適化前 | 最適化後 | 差 |
---|---|---|---|
1 | 0.000001803875 | 0.000001413107 | 0.000000390768 |
2 | 0.000002399206 | 0.000001653671 | 0.000000745535 |
3 | 0.000002686262 | 0.000002104044 | 0.000000582218 |
4 | 0.000003310680 | 0.000002167940 | 0.000001142740 |
5 | 0.000003662825 | 0.000002414465 | 0.000001248360 |
6 | 0.000003905773 | 0.000002634525 | 0.000001271248 |
7 | 0.000004558802 | 0.000002737999 | 0.000001820803 |
8 | 0.000005032063 | 0.000002932310 | 0.000002099753 |
9 | 0.000005578995 | 0.000003361940 | 0.000002217055 |
10 | 0.000006055355 | 0.000003500700 | 0.000002554655 |
11 | 0.000006258249 | 0.000003766298 | 0.000002491951 |
12 | 0.000006690502 | 0.000004018307 | 0.000002672195 |
13 | 0.000007185936 | 0.000004022360 | 0.000003163576 |
14 | 0.000007489681 | 0.000004143476 | 0.000003346205 |
15 | 0.000008211851 | 0.000004441023 | 0.000003770828 |
16 | 0.000008442402 | 0.000004733324 | 0.000003709078 |
17 | 0.000008889675 | 0.000004783630 | 0.000004106045 |
18 | 0.000009706736 | 0.000005150318 | 0.000004556418 |
19 | 0.000009850264 | 0.000005435944 | 0.000004414320 |
20 | 0.000010215759 | 0.000005474091 | 0.000004741668 |
実際には、最適化前コードは大抵後置インクリメントになってることが多いので、もう少し差がでるはずです。
最適化の効果はすぐに結果に現れました。
が、元々の処理時間が短いので、新規で書くのはともかく、現行のコードを直す価値はこの速度差にあるのでしょうか…?
その辺の基準や、0.00001秒の差が及ぼすシステム全体への影響がわかりません。
少なくともユーザーの応答待ちの体感は変わらないと思うのですが。
参考文献
今すぐできるPHP高速化 5つのポイント
少し離れているが、今回と同じような3回ループの比較ができた。
同時にforeach
が速いという結論ですが…
パフォーマンスのためにPHPのfor文でcountを使うべきではない
1000回以上のパフォーマンス比較。
ベンチマークかっこいい。
他にもたくさんあると思いますが、キーワードの違いとかですぐに見失いますね…
大体高速化は2~3倍というのが多いようです。