【編集者注】これまで PHP のパフォーマンス分析に関する記事をたくさん読みましたが、それらはすべてルールを 1 つずつ書いています。さらに、これらのルールにはコンテキストがなく、これらのルールの利点を示す明確な実験もありません。この議論では、いくつかの文法的な点にも焦点を当てています。この記事では、PHP のパフォーマンス分析の視点を変え、PHP のパフォーマンスの注意点や改善が必要な点を例を用いて分析します。
PHP のパフォーマンスを分析するために、この記事を 2 つのレベルに分けます。1 つはマクロ レベルで、もう 1 つは PHP 言語自体のレベルです。レベルは文法と使用規則のレベルですが、規則について説明するだけでなく、例の分析も支援します。
マクロレベル、つまり、PHP 言語自体のパフォーマンス分析は 3 つの側面に分けられます:
1. インタプリタ言語としてのPHPのパフォーマンス分析と改善
PHPはスクリプト言語であり、インタプリタ言語であるため、同時にコンパイルされるため、自然なパフォーマンスは制限されます。実行前にバイナリ コードにコンパイルされる型ベースの言語とは異なり、インタープリタ型言語は、入力、解析、コンパイル、および元のスクリプトの実行のそれぞれの時点で直面します。走る。インタプリタ言語としての PHP の実行プロセスは次のとおりです。
上の図から、各実行で解析、コンパイル、実行の 3 つのプロセスを経る必要があることがわかります。
では、最適化ポイントはどこでしょうか?ファイルは変更されなくなり、入力パラメータの違いにより実行が異なるため、コード ファイルが決まれば、解析からコンパイルまでの手順が決まると考えられます。パフォーマンス最適化の世界では、同じ結果を得ながら操作を減らすことが究極の秘訣です。これが有名なキャッシュです。キャッシュはあらゆる場所で使用されており、キャッシュはパフォーマンスの最適化にとって重要な機能でもあります。そこで、OpCode キャッシュ トリックが登場しました。解析してコンパイルする必要があるのは初回のみで、その後の実行ではスクリプトが直接 Opcode に転送されるため、パフォーマンスが向上します。実行プロセスは次の図に示されています。
スクリプトの解析、コンパイル、読み取りの各処理と比較して、キャッシュからバイトコードを直接読み取る効率はどれくらい向上しますか?
オペコードキャッシュなしで実験してみましょう。同時実行数 20、オペコード キャッシュなしで合計 10,000 リクエスト、次の結果が得られます:
次に、サーバー上でオペコード キャッシュを有効にします。オペコード キャッシュを実装するには、APC、Zend OPCache、および eAccelerator 拡張機能をインストールするだけで済みます。複数の拡張機能がインストールされている場合でも、そのうちの 1 つだけが有効になります。 php.ini 設定を変更した後は、php-fpm 設定を再ロードする必要があることに注意してください。
実験のためにここで APC と Zend OPCache を有効にします。 APC 対応バージョン。
当初は各リクエストが 110 ミリ秒、1 秒あたり 182 リクエストが処理されていましたが、APC を有効にすると 68 ミリ秒になり、1 秒あたり 294 リクエストが処理されるようになりました。速度が約 40% 向上します。
Zend Opcache が有効になっているバージョンでは、結果は APC とほぼ同等です。 1 秒あたり 291 のリクエストを処理し、各リクエストには 68.5 ミリ秒かかります。
上記の実験からわかるように、使用されたテスト ページの 40 ミリ秒以上が構文の解析とコンパイルに費やされました。これら 2 つの操作をキャッシュすることにより、このプロセスの速度が大幅に向上します。
さらに、OpCode とは何ですか? OpCode がバイトコードをコンパイルした後、bytekit などのツールを使用するか、vld PHP 拡張機能を使用して PHP コードをコンパイルできます。以下は、vld プラグイン解析コードを実行した結果です。
コードの各行が対応する OpCode 出力にコンパイルされていることがわかります。
2. 動的型付け言語としての PHP のパフォーマンス分析と改善
2 つ目は、PHP 言語が動的型付け言語であるということです。たとえば、PHP では、2 つの整数を加算すると、整数値と文字が得られます。文字列を加算すること、または 2 つの文字列を加算することも、整数を加算することになります。文字列とあらゆる種類の連結操作は文字列になります。
<?php $a = 10.11; $b = "30"; var_dump($a+$b); var_dump("10"+$b); var_dump(10+"20"); var_dump("10"+"20");
実行結果は次のとおりです:
float(40.11) int(40) int(30) int(30)
言語の動的型付けは開発者に利便性を提供しますが、言語自体は動的型付けにより効率が低下します。 Swift には型推論と呼ばれる機能があり、型推論がどれほど大きな効率差をもたらすかがわかります。型推論を必要とする 2 つの Swift コードと、型推論を必要としない 2 つの Swift コードについて、コンパイルしてどのように動作するかを確認してみましょう。 コードの最初の部分は次のとおりです:
これは Swift コードの一部です。この辞書には 14 個のキーと値のペアしかありません。このコードのコンパイルは 9 分以内に完了しませんでした (5G メモリ、2.4GHz)。 CPU) コンパイル環境は Swift 1.2、Xcode 6.4 です。
しかし、コードを次のように調整すると:
つまり、planeLocation の型推論を回避するために型修飾が追加されます。コンパイルプロセスには 2 秒かかりました。
動的型として付加された型推論操作により、プログラムのコンパイル速度が大幅に低下することがわかります。 もちろん、この例は少し極端であり、Swift 言語自体はまだ進化の過程にあるため、PHP を比較するために Swift を使用するのは適切ではないかもしれません。この例は、プログラミング言語が動的型付け言語の場合、コンパイルの観点から影響を受ける動的型の処理を伴うことのみを示しています。
それでは、動的型としての PHP の効率を向上させるにはどうすればよいでしょうか?コードをどのように記述しても動的に型指定されるため、PHP 言語自体のレベルでは解決策はありません。解決策は、PHP を静的型表現に変換することです。つまり、Yaf フレームワークなど、Niao 兄弟のプロジェクトの多くが拡張機能になっていることがわかります。 Cマスターです。拡張機能は C または C++ で記述されているため、動的型ではなくなり、さらにコンパイルされるため、C 言語自体の効率が大幅に向上します。したがって、効率が大幅に向上します。
コードの一部を見てみましょう。このコードは単純な素数演算のみを実装しており、指定された値内の素数の数を計算できます。次に、拡張実装と PHP のネイティブ実装の効率の違いを見てみましょう。もちろん、この違いは動的型とコンパイル型の違いだけでなく、言語の効率の違いでもあります。
1 つ目は、1,000 万個以内の素数を計算するための純粋な PHP で書かれたアルゴリズムです。3 回の実験を行った後も、結果は基本的に同じです。
次に、素数の数を求めるこの処理を PHP 拡張機能に記述し、その拡張機能に整数を入力し、その整数より小さい素数を返す getprimenumbers 関数を実装しました。得られた結果は以下の通りで、この効率化は非常に素晴らしく、約1.4秒で復帰します。 20 倍以上高速になります。
ご想像のとおり、静的言語とコンパイル言語の効率は驚くほど向上しました。このプログラムの C 言語コードは次のとおりです:
PHP_FUNCTION(get_prime_numbers) { long value; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &value) == FAILURE) { return; } int *numbers = (int *)malloc(sizeof(int)*128*10000); memset(numbers, 0x0, 128*10000); int num = 2; numbers[0] = 2; numbers[1] = 3; bool flag = true; double f = 0; int i = 0; int j = 0; for(i=5; i<=value; i+=2) { flag = true; f = sqrt(i); for(j=0; j<num;j++) { if(i%numbers[j]==0) { flag = false; break; } if(numbers[j]>f) { break; } } if(flag) { numbers[num] = i; num++; } } free(numbers); RETURN_LONG(num); }
3. PHP 言語自体の基礎となるパフォーマンス エンジンの改善
パフォーマンス最適化の 3 番目のレベルは、言語自体のパフォーマンスの向上であり、通常のレベルを超えています。開発者はできるのです。 PHP 7 より前では、小規模バージョンでの改善が期待されましたが、その改善はそれほど顕著ではありませんでした。たとえば、PHP 5.3、PHP 5.4、PHP 5.5、および PHP 5.5 の間で同じコードのパフォーマンスを比較すると、ある程度の改善。
上記の例では PHP 5.3 バージョンについて説明しましたが、これには約 33 秒かかります。次に、他の PHP バージョンを見てみましょう。動作は以下の通りです:
PHP バージョン 5.4 はバージョン 5.3 に比べてある程度改善されました。約6秒速くなりました。
PHP バージョン 5.5 は、PHP 5.4 に基づいてさらに一歩前進し、6S 高速になっています。
PHP5.6 は少し遅れています。
PHP 7 は本当に驚くべき効率向上を実現しており、PHP5.3 の 3 倍以上です。
上記は、さまざまな PHP バージョン間の素数スクリプトの実行速度の違いを見つけるためのものです。このプログラムのみをテストしましたが、特に厳密ではありませんが、同じマシン上で実行され、コンパイル設定パラメーターは次のとおりです。基本的には同じですが、ある程度の比較可能性はあります。
マクロレベルでは、上記に加えて、実際のデプロイメントプロセスにおいて、PHPパフォーマンスの最適化は、運用中に消費されるリソースの削減にも反映されます。したがって、FastCGI モードと mod_php モードも、従来の CGI モードよりも人気があります。従来の CGI モードでは、スクリプトを実行するたびにすべてのモジュールをロードする必要があるためです。プログラムの実行が終了したら、モジュールのリソースも解放する必要があります。以下の図に示すように:
FastCGI および mod_php モードでは、これは必要ありません。 php-fpm または Apache を起動する場合にのみ、特定の実行プロセス中にすべてのモジュールを一度ロードする必要があり、関連するモジュール リソースを再度ロードして解放する必要はありません。
このようにして、プログラムのパフォーマンスの効率が向上しました。以上が PHP のマクロレベルでのパフォーマンス最適化の分析でした。この記事の後半では、アプリケーション関連の PHP 最適化ガイドラインについて説明します。乞うご期待!
上記では、PHP のパフォーマンス分析と実験について紹介しました。内容の側面も含めたパフォーマンスのマクロ分析が、PHP チュートリアルに興味のある友人に役立つことを願っています。