ホームページ >バックエンド開発 >PHPチュートリアル >PHP オペコード – コードを変更せずにアプリケーションのパフォーマンスを向上させる
PHP エンジンによって生成される PHP オペコードは、コードの記述方法に強く影響されます。タスクを達成するためのステートメントの数だけではありません。それが非常に重要であることは明らかであり、あなたにとっても明らかだと思います。
あまり明らかではないかもしれませんが、コードの構文によっても生成されるオペコードが完全に変更され、マシンの CPU がまったく同じコードを実行する際に多大なオーバーヘッドが発生する可能性があるということです。
ここ数年で、私の SaaS 製品は大幅に成長し、ワークロードを可能な限り効率的に実行するための最適化手法をさらに深く掘り下げる機会が与えられました。
私が見た結果は印象的で、SaaS の開発を継続するためのフリー キャッシュ フローを解放するのに大いに役立ちました。
現時点で、私の SaaS 製品内の PHP プロセスは、2vCPU と 8GB のメモリを搭載したマシンで毎日 12 億 (B の場合) 以上のデータ パケットを処理しています。 予期せぬスパイクが発生した場合の柔軟性を高めるために AWS 自動スケーリング グループを使用していますが、2 台目のマシンが追加されることはめったにありません (週に 1 ~ 2 回)。
さらに技術的な記事については、Linkedin または X で私をフォローしてください。
最近、Inspector サーバーの ARM インスタンスへの移行についても書きました: https://inspector.dev/inspector-adoption-of-graviton-arm-instances-and-what-results-weve-seen/
記事の本題に入りましょう。とても興味深い内容だと思います。
PHP オペコードはオペレーション コードの略で、作成した PHP ソース コードがコンパイルされた後に PHP エンジンによって実行される低レベルの命令を指します。
PHP では、コードのコンパイルは実行時に行われます。基本的に、コードが初めて PHP エンジンに取り込まれるときに、コードはこのマシンに適したコードにコンパイルされ、キャッシュされるため、エンジンは同じコードを再度コンパイルしません。その後実行されます。
これはプロセスを簡単に表したものです:
PHP オペコードをキャッシュすると、コード実行プロセスの 3 つのステップ (生の PHP コードの解析、トークン化、コンパイル) を節約できます。
オペコードが初めて生成されると、後続のリクエストで再利用できるようにメモリに保存されます。これにより、PHP エンジンが同じ PHP コードを実行するたびに再コンパイルする必要が減り、CPU とメモリの消費量が大幅に節約されます。
PHP で最も一般的に使用されるオペコード キャッシュは OPCache で、PHP 5.5 から最近のバージョンまではデフォルトで含まれています。非常に効率的で、広くサポートされています。
プリコンパイルされたスクリプトのバイトコードをキャッシュするには、展開のたびにキャッシュを無効にする必要があります。変更されたファイルのバイトコード バージョンがキャッシュにある場合、PHP は古いバージョンのコードを実行し続けるためです。オペコード キャッシュをパージするまでは、新しいコードが再度コンパイルされて新しいキャッシュ アイテムが生成されます。
さまざまな構文がスクリプトのオペコードにどのような影響を与えるかを理解するには、PHP エンジンによって生成されたコンパイル済みコードを取得する方法が必要です。
オペコードを取得するには 2 つの方法があります。
マシン上で OPCache 拡張機能を有効にしている場合は、そのネイティブ関数を使用して特定の PHP ファイルのオペコードを取得できます。
// Force compilation of a script opcache_compile_file(__DIR__.'/yourscript.php'); // Get OPcache status $status = opcache_get_status(); // Inspect the script's entry in the cache print_r($status['scripts'][__DIR__.'/yourscript.php']);
VLD は、コンパイルされた PHP コードを逆アセンブルし、オペコードを出力する一般的な PHP 拡張機能です。これは、PHP がコードをどのように解釈して実行するかを理解するための強力なツールです。インストールしたら、-d オプションを指定した php コマンドを使用して、VLD を有効にして PHP スクリプトを実行できます。
php -d vld.active=1 -d vld.execute=0 yourscript.php
出力には、各操作、それに関連するコード行など、コンパイルされたオペコードに関する詳細情報が含まれます。
3v4l は、エディターに入力した PHP コードによって生成されたオペコードを表示できる非常に便利なオンライン ツールです。基本的には、VLD がインストールされた PHP サーバーであるため、VLD 出力を取得し、オペコードをブラウザーに表示できます。
無料で配布されているため、次の分析にはこのオンライン ツールを使用します。
3v4l は、使用するコード構文が結果の PHP オペコードに良い意味でも悪い意味でもどのように影響するかを理解するのに最適です。以下のコードを 3v4l に貼り付け始めましょう。設定を「サポートされているすべてのバージョン」のままにして、「評価」をクリックします。
<?php namespace App; strlen('ciao');
コードを実行すると、下部にタブ メニューが表示されます。 [VLD] タブに移動して、対応する OPcode を視覚化します。
line #* E I O op fetch ext return operands ------------------------------------------------------------------------------------- 5 0 E > INIT_NS_FCALL_BY_NAME 'App%5CSpace%5Cstrlen' 1 SEND_VAL_EX 'ciao' 2 DO_FCALL 0 3 > RETURN 1
最初の操作は INIT_NS_FCALL_BY_NAME であることに注意してください。インタプリタは、現在のファイルの名前空間を使用して関数の名前を構築します。しかし、AppExample 名前空間には存在しないので、どのように機能するのでしょうか?
インタプリタは、関数が現在の名前空間に存在するかどうかを確認します。そうでない場合は、対応するコア関数を呼び出そうとします。
ここでは、この二重チェックを回避し、コア関数を直接実行するようにインタープリタに指示する機会があります。
strlen の前にバックスラッシュ () を追加して、「eval」をクリックしてみてください:
<?php namespace App; \strlen('ciao');
[VLD] タブで、ステートメントを 1 つだけ含むオペコードを確認できるようになりました。
line #* E I O op fetch ext return operands ------------------------------------------------------------------------------------- 5 0 E > > RETURN 1
これは、関数の正確な場所を伝えたため、フォールバックを考慮する必要がありません。
バックスラッシュを使用したくない場合は、他のクラスと同様にルート名前空間から関数をインポートできます。
// Force compilation of a script opcache_compile_file(__DIR__.'/yourscript.php'); // Get OPcache status $status = opcache_get_status(); // Inspect the script's entry in the cache print_r($status['scripts'][__DIR__.'/yourscript.php']);
PHP エンジンには、静的式を事前に評価して最適化されたオペコードを生成するための内部自動機能も多数あります。これは、バージョン 7.x
以降、PHP のパフォーマンスが大幅に向上した最も重要な理由の 1 つです。これらのダイナミクスを認識することは、リソースの消費量を削減し、コストを削減するのに非常に役立ちます。この調査を行った後、コード全体でこれらのトリックを使用し始めました。
PHP 定数を使用した例を示します。このスクリプトを 3v4l で実行します:
php -d vld.active=1 -d vld.execute=0 yourscript.php
PHP オペコードの最初の 2 行を見てください:
<?php namespace App; strlen('ciao');
FETCH_CONSTANT は、現在の名前空間から PHP_OS の値を取得しようとします。ここには存在しないため、グローバル名前空間が調べられます。次に、IS_IDENTICAL 命令によって IF ステートメントが実行されます。
次に、定数にバックスラッシュを追加してみます:
line #* E I O op fetch ext return operands ------------------------------------------------------------------------------------- 5 0 E > INIT_NS_FCALL_BY_NAME 'App%5CSpace%5Cstrlen' 1 SEND_VAL_EX 'ciao' 2 DO_FCALL 0 3 > RETURN 1
オペコードでわかるように、エンジンは定数がどこにあるかが明確であり、静的な値であるためメモリにすでに存在しているため、エンジンは定数を取得しようとする必要がありません。
また、IS_IDENTITCAL ステートメントの反対側が静的文字列 ('Linux') であるため、IF ステートメントが消えました。そのため、実行のたびに解釈するオーバーヘッドなしで IF を「true」としてマークできます。
これが、PHP コードの最終的なパフォーマンスに影響を与える大きな力を持っている理由です。
記事の冒頭で述べたように、この戦術を使用することで多くのメリットが得られており、実際にパッケージでも使用されています。
興味深いトピックだったと思います。このヒントを PHP パッケージで使用してパフォーマンスを最適化した例をここで見ることができます: https://github.com/inspector-apm/inspector-php/blob/master/src/Inspector.php# L302
さらに技術的な記事については、Linkedin または X で私をフォローしてください。
Inspector は、ソフトウェア開発者向けに特別に設計されたコード実行監視ツールです。サーバーレベルで何もインストールする必要はありません。Laravel または Symfony パッケージをインストールするだけで準備完了です。
HTTP モニタリング、データベース クエリに関する洞察、アラートや通知を好みのメッセージング環境に転送する機能をお探しの場合は、Inspector を無料でお試しください。アカウントを登録してください。
または、Web サイトで詳細をご覧ください: https://inspector.dev
以上がPHP オペコード – コードを変更せずにアプリケーションのパフォーマンスを向上させるの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。