ホームページ  >  記事  >  バックエンド開発  >  php_PHP チュートリアルで in_array のパフォーマンスが低い問題が発生しました

php_PHP チュートリアルで in_array のパフォーマンスが低い問題が発生しました

WBOY
WBOYオリジナル
2016-07-21 16:12:47810ブラウズ

PHP のパフォーマンスは常に向上しています。ただし、不適切に使用したり、注意を怠ったりすると、PHP の内部実装の落とし穴に陥る可能性があります。数日前にパフォーマンスの問題が発生しました。

問題は次のようなものです。私たちのインターフェイスの 1 つが戻るのに毎回 5 秒かかると同僚が報告しました。私たちは一緒にコードを確認しましたが、実際には読み取りキャッシュがループ内で呼び出されていることに「驚きました」。 900 回) の操作を実行しましたが、キャッシュされたキーは変更されていないため、このコードをループの外に移動して再度テストすると、インターフェイスの戻り時間が 2 秒に短縮されました。倍増しましたが、明らかに受け入れられる結果ではありません。
パフォーマンスの問題を引き起こしたコードの量はそれほど多くなかったので、IO の問題を解決した後、テスト コードを作成しましたが、案の定、すぐに問題が再発しました。

コードをコピーします コードは次のとおりです:

$y="1800";
$x = array(); ;$j++ ){
$x[]= "{$j}"
}

for($i=0;$i<3000;$i++){
if(in_array($y,$x)) {
続行 ;
}
}
?>


shell$ time /usr/local/php/bin/php test.php

real 0m1.132s
sys 0m0.015s

はい、文字列型の数値を使用しています。キャッシュから取り出すと次のようになります。そこで、ここでは特別に文字列に変換しています(直接数値であればこの問題は発生しません。自分で確認できます)。消費される時間は 1 秒で、これはわずか 3000 サイクルであることがわかります。また、その後のシステム時間も strace を使用しても有効な情報が得られないことがわかります。

shell$ strace -ttt -o xxx /usr/local/php/bin/php test.php
shell$less xxx



in_array.strace これら 2 つのシステムコール間の遅延が非常に大きいことだけがわかります。何をしたのか分かりませんか?幸いなことに、Linux のデバッグ ツールには strace に加えて ltrace も含まれています (もちろん、dtrace や ptrace もありますが、これらはこの記事の範囲外なので省略します)。

引用: strace はプロセスのシステムコールまたはシグナル生成を追跡するために使用され、ltrace はライブラリ関数を呼び出すプロセスを追跡するために使用されます (IBM 開発者ワークス経由)。

干渉要因を排除するために、結果に影響を与える過剰な malloc 呼び出しを避けるために、$x を array("0","1","2",…) の形式に直接割り当てます。

shell$ ltrace -c /usr/local/php/bin/php test.php を実行します

図 2 に示すように



in_array.ltrace1
ライブラリ関数 __strtol_internal が非常に頻繁に呼び出されており、94% に達していることがわかります。あまりにも大げさなので、このライブラリ関数 __strtol_internal が何をしているのか調べてみると、これは strtol のエイリアスであることがわかり、これは PHP エンジンがそれを検出したと推測できます。この変換プロセスは時間がかかりすぎるため、再度実行します:



コードは次のとおりです: shell$ ltrace -e "__strtol_internal " /usr/local/php/bin/php test.php

この時点で、次のような大まかな比較が見つかります。 in_arrayは2つの文字列をlong integerに変換してから比較しますが、これでパフォーマンスが消費されるかどうかはわかりません。



問題の核心はわかったので、解決策はたくさんあります。最も簡単な方法は、in_array の 3 番目のパラメーターを true に追加することです。これは、厳密な比較となり、型が同時に比較されることを意味します。これにより、PHP が賢くなりすぎることを回避でき、コードは次のようになります。
tu3

コードをコピーします

コードは次のとおりです:

$y="1800";$x = array();
for($j=0;$j<2000 ;$j++) {
$x[]= "{$j}";
}

for($ i = 0; $ i&lt; 3000; $ i ++){


コードをコピーします

コードは次のとおりです:


shell$ time /usr/local/php/bin/php test.php

real 0m0.267s user 0m0.247s

sys 0m0.020s



何倍も速い! ! ! sys にかかる時間はほとんど変わっていないことがわかります。もう一度 ltrace を実行するときも、malloc 呼び出しの干渉を排除するために $x を直接割り当てる必要があります。実際のアプリケーションではキャッシュから一度に取得するため、サンプル コードのようなループは適用されません。メモリ。
再度実行

コードをコピーします コードは次のとおりです:

shell$ ltrace -c /usr/local/php/bin/php test.php


以下に示すように:

in_array.ltrace2

__ctype_to lower_loc が最も時間を要します。ライブラリ関数 __ctype_to lower_loc の機能を確認しました。簡単に理解すると、文字列を小文字に変換することになります。つまり、in_array の比較文字列では大文字と小文字が区別されないということですか?実際、この関数呼び出しは in_array とはほとんど関係がありません。in_array の実装については、PHP のソース コードを見たほうがよいでしょう。これ以上は説明できません。私とのコミュニケーションを歓迎します。間違ったことを書いた場合は修正してください。

——————2013.08.29 分割線——————————

夕方、以下の PHP 5.4.10 のソースコードを読み直しました。in_array にとても興味があります(笑)。 /ext/standard/array.c の 1248 行目で、php_search_array 関数を呼び出していることがわかります。ただし、最後のパラメータが異なります。いくつかの追跡の後、in_array の緩い比較の場合、彼は最終的に ./Zend/zend_operators.c にある関数 zendi_smart_strcmp (実際には「スマート」関数) を比較のために呼び出しました。 ltrace を使用して、大量のキャプチャされたデータを変換しました。整数への変換は is_numeric_string_ex の動作です。

%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7-2013-08-29-23.13.20

関数 is_numeric_string_ex は ./Zend/zend_operators.h で定義されています。一連の判断と変換の後、strtol が 232 行目で呼び出され、文字列を次のように変換します。長整数、写真と真実があります

zend_operators-is_num

www.bkjia.comtru​​ehttp://www.bkjia.com/PHPjc/313618.html技術記事 PHP のパフォーマンスは常に向上しています。ただし、不適切に使用したり、注意を怠ったりすると、PHP の内部実装の落とし穴に陥る可能性があります。数日前にパフォーマンスの問題が発生しました...
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。