2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

forの公式通りの最適化 at 低回数

Last updated at Posted at 2015-10-26

特に目新しい要素はありません。

Q

低回数のforループでも最適化したほうがいい?

A

何回でも最適化したほうがいい。
大体1.5~2倍早くなる…かも。

概要

forの最適化は公式にものっていますが、巷の速度検証はパッと見

  1. for,foreach,whileの比較
  2. 10000回以上のループ時の最適化結果

などがよく出てきます。
でも、実際使うループって、ちっさい奴の方が多くて、多くて数十回。
条件によるが、1,2回が多いよーってループもあります。

そんなループが毎回countしているとして、それを最適化するべきか。

  1. 改善したとして、2,3回のループでは誤差の範囲なのでは?
  2. 変数を増やすことで、低回数では逆転現象が起きるのでは?

という、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倍というのが多いようです。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?