[解決済み] PHPにおけるFORとFOREACHの性能比較
質問
まず最初に、90% のアプリケーションでは性能差はまったく関係ないことを理解していますが、どちらがより速い構成であるかを知る必要があります。それと...
現在、ネット上でそれらについて入手できる情報は混乱しています。多くの人が foreach は良くないと言いますが、技術的には、foreach はイテレータを使用して配列の走査を書くことを単純化すると考えられているので、より速くなるはずです。イテレータもまた高速になるはずなのですが、PHPではどうやら死ぬほど遅いようです(これはPHPのことではないのでしょうか)。私は配列関数について話しています: next() prev() reset() など、もしそれらが関数であり、関数のように見えるPHP言語の機能の1つでないなら。
これを少し狭めるために : 私は 1 以上のステップで配列を走査することに興味がありません (負のステップもありません。つまり、逆反復です)。また、0から長さまでの任意の点への、または任意の点からの走査にも興味がありません。また、1000以上のキーを持つ配列を操作することは日常的にありませんが、アプリケーションのロジックの中で何度も配列を走査することはあります。また、操作としては、主に文字列の操作とエコーのみです。
参考サイトをいくつか紹介します。
http://www.phpbench.com/
http://www.php.lt/benchmark/phpbench.php
どこでも聞く話
-
foreach
は遅いのでfor
/while
が速い -
PHP
foreach
は反復処理する配列をコピーします。これを高速化するには、参照 -
のようなコードになります。
$key = array_keys($aHash); $size = sizeOf($key);
は
for ($i=0; $i < $size; $i++)foreach
私の問題はここにあります。私はこのテストスクリプトを書きました。 http://pastebin.com/1ZgK07US を書きましたが、何度スクリプトを実行しても、次のようなものが表示されます。
foreach 1.1438131332397
foreach (using reference) 1.2919359207153
for 1.4262869358063
foreach (hash table) 1.5696921348572
for (hash table) 2.4778981208801
要するに
-
foreach
よりも高速です。foreach
参照で -
foreach
よりも高速です。for
-
foreach
よりも高速です。for
ハッシュテーブルの場合
誰か説明してください。
- 私は何か間違ったことをしているのでしょうか?
- PHPのforeachの参照は本当に違いがあるのでしょうか?つまり、なぜ参照渡しをするとコピーされないのでしょうか?
- ネット上でいくつか見かけましたが、それらをテストするたびにタイミングがずれてしまいます。また、いくつかの簡単なイテレータ構成をテストしましたが、まともな結果すら得られないようです。
- FOR/FOREACH (および WHILE) 以外に、配列を反復処理する高速な方法/メソッド/構造はありますか?
PHP バージョン 5.3.0
編集: 回答 ここの人々の助けで、私はすべての質問に対する答えをまとめることができました。ここでそれらを要約します。
- "私は何か間違ったことをしているのでしょうか。 ベンチマークで echo を使うことはできない、というのがコンセンサスのようです。個人的には、echo がランダムな実行時間を持つ関数であることや、他の関数がどう違うのかがまだわかりません。また、foreach の結果とまったく同じものを生成するスクリプトの能力は、単に echo" を使っている(私は何を使うべきだったのか)と説明するのは難しいものです。しかし、私はテストがより良い何かで行われるべきであることを認めます;しかし、理想的な妥協は思い浮かびません。
- PHP の foreach 参照というのは本当に違いがあるのでしょうか。つまり、参照渡しの場合、なぜコピーしないのでしょうか。 ircmaxellは、そうであることを示しています。さらなるテストにより、ほとんどの場合、参照の方が高速であることが証明されたようです -- 私の上記のコードの断片を考えると、ほとんどがすべてというわけではありませんが。私は、この問題はおそらくこのようなレベルで悩むにはあまりにも非直感的で、それぞれの状況に対してどちらが良いかを実際に判断するには、デコンパイルなどの極端なものが必要であることを認めます。
- ネット上でいくつか見かけましたが、テストするたびにタイミングがずれてしまいます。また、いくつかの簡単なイテレータをテストしましたが、まともな結果すら得られないようです。 ircmaxell が以下のような答えを出してくれました。ただし、このコードは PHP のバージョン >= 5 でしか有効ではないかもしれません。
- FOR/FOREACH (および WHILE) 以外に、配列を反復処理するための高速な方法/メソッド/構造はありますか? 回答してくれた Gordon に感謝します。PHP5で新しいデータ型を使用すると、パフォーマンスとメモリのどちらかが向上します(状況によっては、どちらかが望ましいかもしれません)。速度面では、多くの新しい型の配列は array() よりも優れていないように見えますが、 splpriorityqueue と splobjectstorage は大幅に高速化されているようです。リンクは Gordon によって提供されました。 http://matthewturland.com/2010/05/20/new-spl-features-in-php-5-3/
助けようとしてくれた皆さん、ありがとうございました。
単純なトラバーサルにはforeach(非参照バージョン)にこだわることになりそうです。
どのように解決するのですか?
私の個人的な意見としては、文脈の中で意味をなすものを使うことです。 個人的には、私はほとんど
for
を配列の走査に使うことはほとんどありません。 他のタイプの反復処理には使いますが
foreach
はあまりに簡単なので...。 ほとんどの場合、時間差はほとんどないでしょう。
大きな注意点としては
for ($i = 0; $i < count($array); $i++) {
これは高価なループです。なぜなら、1回ごとの反復でカウントを呼び出すからです。そんなことをしない限りは、特に問題ないと思うのですが...。
参照の違いについては、PHPはコピーオンライトを使用しているので、配列に書き込まないのであれば、ループ中のオーバーヘッドは比較的少なくて済みます。 しかし、配列内で配列を変更し始めると、両者に違いが出てきます (一方は配列全体をコピーする必要があり、参照はインラインで変更すればよいからです)...
イテレータについては
foreach
とは同等です。
$it->rewind();
while ($it->valid()) {
$key = $it->key(); // If using the $key => $value syntax
$value = $it->current();
// Contents of loop in here
$it->next();
}
反復処理にもっと速い方法があるかというと、それは本当に問題によります。 しかし、私は本当に、なぜなのか、と問う必要があります。 物事をより効率的にしたいことは理解できますが、マイクロ最適化のために時間を浪費しているように思います。 覚えておいてください。
Premature Optimization Is The Root Of All Evil
...
編集する。 コメントに基づいて、私は簡単なベンチマークを実行することにしました...。
$a = array();
for ($i = 0; $i < 10000; $i++) {
$a[] = $i;
}
$start = microtime(true);
foreach ($a as $k => $v) {
$a[$k] = $v + 1;
}
echo "Completed in ", microtime(true) - $start, " Seconds\n";
$start = microtime(true);
foreach ($a as $k => &$v) {
$v = $v + 1;
}
echo "Completed in ", microtime(true) - $start, " Seconds\n";
$start = microtime(true);
foreach ($a as $k => $v) {}
echo "Completed in ", microtime(true) - $start, " Seconds\n";
$start = microtime(true);
foreach ($a as $k => &$v) {}
echo "Completed in ", microtime(true) - $start, " Seconds\n";
そして、その結果。
Completed in 0.0073502063751221 Seconds
Completed in 0.0019769668579102 Seconds
Completed in 0.0011849403381348 Seconds
Completed in 0.00111985206604 Seconds
つまり、ループ内で配列を修正するのであれば、参照を使った方が数倍速い...ということです。
そして、参照だけのオーバーヘッドは、実際には配列をコピーするよりも少ないのです(これは5.3.2での話です)... つまり、(少なくとも 5.3.2 では) 参照の方が著しく高速であるように見えるのです...。
EDITです。 PHP8.0を使用すると、以下のようになりました。
Completed in 0.0005030632019043 Seconds
Completed in 0.00066304206848145 Seconds
Completed in 0.00016379356384277 Seconds
Completed in 0.00056815147399902 Seconds
このテストは何度も繰り返され、ランキングの結果は一貫していました。
関連
-
[解決済み】「初期通信パケットの読み込み」でMySQLサーバーに接続できなくなり、システムエラーになる。0
-
[解決済み] mysql_field_nameを新しいmysqliに変更します。
-
[解決済み] SQLiteのINSERT/per-secondのパフォーマンスを向上させる
-
[解決済み] PHPで配列から要素を削除する
-
[解決済み] JavaScriptで配列を比較する方法は?
-
[解決済み] PHP の配列を保存するための好ましい方法 (json_encode vs serialize)
-
[解決済み】PHPの'foreach'は実際どのように動作するのですか?
-
[解決済み] Intel CPU の _mm_popcnt_u64 で、32 ビットのループカウンターを 64 ビットに置き換えると、パフォーマンスが著しく低下します。
-
[解決済み】PHPパスワードのハッシュとソルトの安全性について
-
[解決済み] リファレンス - このシンボルはPHPで何を意味するのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] [Solved] Fatal error: メンバ関数prepare()のNULLでの呼び出し
-
[解決済み】空の配列要素を削除する
-
[解決済み】XAMPPのphpMyAdminで「設定にあるcontroluserの接続に失敗しました。
-
[解決済み] SQLSTATE[HY093]: 無効なパラメータ番号: バインドされた変数の数が102行目のトークンの数と一致しない [終了]
-
[解決済み】Chrome net::ERR_INCOMPLETE_CHUNKED_ENCODING エラーが発生しました。
-
[解決済み】file_get_contents( )が動作しない。
-
[解決済み】書き込みコンテキストでメソッドの戻り値を使用することができない
-
[解決済み] Uncaught Error: 未定義の関数 mysql_escape_string() の呼び出し。
-
[解決済み】MySQLのカラム数が1行目の値数と一致しない【非公開
-
[解決済み] PHP product.php?id=1 のような URL を作成する方法