PHP GR8:JITはPHP 8のパフォーマンスを改善します





PHPはBadooの主要な開発言語の1つです。 データセンターでは、数千のプロセッサコアが数百万行のPHPコードの実行に追われています。 ボリュームを少しでも最適化してもリソースを大幅に節約できるため、ニュースを注意深く追って生産性を向上させる方法を積極的に探しています。 PHPの主要なパフォーマンスニュースの1つは、言語の8番目のバージョンにJITが登場したことです。 もちろん、これは私たちの注意なしに残ることはできませんでした。JITとは何か、PHPでの実装方法、それを行うことを決定した理由、およびそれから期待することに関する記事を翻訳しました。



あなたが洞窟を去らなかった、または過去から来なかった場合(この場合、歓迎)、PHP 8がJITを持っていることをすでに知っています。 。



写真のように、いくつかのクレイジーな動きを喜びで表現することもできます(ちなみに、これは「デトロイトJIT」と呼ばれています:







さあ、座ってこの神話を暴く記事を読んでください。 JITとは何か、それがどのように役立つかに関する誤解を明確にし、それがどのように機能するかについて説明します(ただし、あまり詳しくないので、退屈しません)。



誰が記事を読むかわからないので、簡単な質問から複雑な質問に進みます。 タイトルの質問に対する答えがすでにわかっている場合は、対応する章を安全にスキップできます。



JITとは



PHPは、仮想マシン(Zend VMと呼びます)に基づいて実装されています。 この言語は、PHPソースコードを仮想マシンが理解できる命令にコンパイルします(これをコンパイルステージと呼びます)。 コンパイル段階で取得された仮想マシンの命令は、オペコードと呼ばれます。 ランタイム段階で、Zend VMはオペコードを実行し、必要な作業を実行します。



この回路はうまく機能します。 さらに、APC(以前)やOpCache(今日)などのツールはコンパイルステージの結果をキャッシュするため、このステージは必要な場合にのみ実行されます。



要するに、JITはジャストインタイムコンパイル戦略(適切なタイミング)であり、最初にコードが中間表現に変換され、次に実行中にアーキテクチャ依存のマシンコードに変換されます。



PHPでは、これは、JITがコンパイル段階で受け取った仮想マシンの命令を中間表現と見なし、Zend VMではなくプロセッサによって直接実行されるマシンコードを発行することを意味します。



PHPにJITが必要なのはなぜですか?



PHP 7.0が登場する少し前、PHPチームの主な焦点は言語のパフォーマンスでした。 PHP 7.0の主要な変更のほとんどはPHPNGパッチにあり、PHPがメモリとプロセッサを使用する方法を大幅に改善しました。 それ以来、私たち一人一人は言語のパフォーマンスを見なければなりません。



PHP 7.0のリリース後、パフォーマンスの改善は継続しました:ハッシュテーブルの最適化(PHPのメインデータ構造)、Zend VMの特定のオペコードの特殊化、コンパイラーの特定のシーケンスの特殊化が導入され、オプティマイザー(OpCacheコンポーネント)は常に改善され、他の多くの変更が実装されました。



厳しい真実は、これらすべての最適化の結果として、生産性向上の機会の限界にすぐに近づいているということです。



注意:「改善の機会の制限」とは、さらなる改善のためにあなたがしなければならないトレードオフがもはや魅力的に見えないという事実を意味します。 パフォーマンスの最適化に関しては、常にトレードオフについて話します。 多くの場合、生産性のために、単純さを犠牲にしなければなりません。 誰もが最も単純なコードも最速だと考えたいと思うでしょうが、Cプログラミングの現代の世界ではそうではありません。 最も高速なのは、アーキテクチャの内部構造またはプラットフォーム/コンパイラに組み込まれた構造を利用するために準備されたコードです。 シンプルさだけでは、パフォーマンスの向上は保証されません。



したがって、この段階で、PHPのパフォーマンスをさらに向上させる最善の方法は、JITを実装することです。



JITは私のサイトを高速化しますか?



おそらく、取るに足らない。



これはあなたが期待していた答えではないかもしれません。 実際、一般的に、PHPアプリケーションは入出力(I / Oバインド)によって制限され、JITはプロセッサ(CPUバインド)によって制限されるコードで最適に動作します。



「I / Oおよびプロセッサによる制限」とはどういう意味ですか?



一部のコードまたはアプリケーションの全体的なパフォーマンスの特性を説明するために、「入出力によって制限される」および「プロセッサによって制限される」という用語を使用します。



最も単純な定義:





コードとアプリケーションは、I / O、プロセッサ、またはその両方によって制限されます。



一般に、PHPアプリケーションはI / Oによって制限される傾向があります。その主なボトルネックは、多くの場合、データベース、キャッシュ、ファイル、ソケットなどへの接続、読み取り、書き込みなどのI / O操作です。



プロセッサ制限されたPHPコードはどのように見えますか?



おそらく、一部のPHPプログラマーは、ほとんどのPHPアプリケーションの性質により、プロセッサが制限されたコードを初めて使用します。通常、データベースまたはキャッシュへのリンクとして機能し、少量のHTML / JSON / XML応答を取得して生成します。



コードベースを見て、I / Oとは関係のないコード、I / Oとは関係のない関数を呼び出すコードを見つけることができます。 また、コードには動作よりもI / Oで動作しない行が多くありますが、これによってアプリケーションプロセッサが制限されるわけではないことに混乱するかもしれません。



実際、PHPは最も高速なインタープリター言語の1つです。 Zend VMとマシンコードでI / Oを使用しない関数の呼び出しに顕著な違いはありません。 もちろん、多少の違いはありますが、マシンコードとZend VMの両方が呼び出し規約を使用しているため、オペコードまたはマシンコードで-___()



を呼び出して-___()



問題ありません-これは顕著な効果はありません呼び出しを行うアプリケーション全体のパフォーマンス。



注:簡単に言えば、呼び出し規約とは、別の関数入るに実行される一連の命令です。 どちらの場合も、呼び出し規約は引数をスタックに渡します。



「ループ、テールコールなどはどうですか?」 PHPは十分にスマートです。OpCacheのオプティマイザーを有効にすると、コードは魔法のように、作成したコードのより効率的なバージョンに変換されます。



ここで、JITはZend VMの呼び出し規約を変更しないことに注意してください。 これは、PHPがJITモードとVMモードをいつでも切り替えることができる必要があるためです(したがって、現在の規則を維持することにしました)。 その結果、JITを使用してどこでも表示される呼び出しは、それほど速く動作しません。



プロセッサに制限のあるPHPコードがどのように見えるかを確認するには、 https//github.com/php/php-src/blob/master/Zend/bench.phpをご覧ください 。 これは極端な例ですが、JITの素晴らしさはすべて数学で明らかにされていることを示しています。



PHPで数学的計算を高速化するために、このような極端な妥協をしなければなりませんでしたか?



いや これは、言語の適用範囲を拡大する(および大幅に拡大する)ために行いました。



自慢したくありませんが、PHPはWebを支配しています。 Web開発に携わっており、次のプロジェクトでPHPを使用することを検討していない場合、何か間違ったことをしていることになります(非常に偏ったPHP開発者の意見です)。



一見すると、PHPでの数学計算の高速化は非常に狭い用途に思えます。 ただし、これにより、たとえば機械学習、3Dレンダリング、2Dレンダリング(GUI)、データ分析などが可能になります。



なぜこれをPHP 7.4で実装できないのですか?



上記で、私はJITを極端な妥協案と呼んでおり、本当にそう思います。これは、既存のすべての中で最も難しいとはいえないにしても、最も難しいコンパイル戦略の1つです。 JITを実装すると、複雑さが大幅に増加します。



JITの作者であるDmitryに、PHPを複雑にしたかどうかを尋ねると、「いいえ、私は複雑さが嫌いです」(これは引用です)と答えます。



基本的に、「複雑」とは「理解できないもの」を意味します。 そして今日、既存のJIT実装を本当に理解している言語開発者はほとんどいません。



PHP 7.4の作業は急速に進んでおり、このバージョンでのJITの導入により、言語をデバッグ、修正、および改善できるのはごく少数になります。 これは、PHP 7.4でJITに反対票を投じた人には受け入れられません。



PHP 8のリリース前に、私たちの多くはJIT実装を理解していました。 実装したい機能と、8番目のバージョン用に書き直したいツールがあります。そのため、最初にJITを理解する必要があります。 今回が必要です。そして、私たちにそれを与えるために大多数が投票したことを非常に感謝しています。



複合体はひどいものと同義ではありません。 複雑さは星の星雲のように美しい場合がありますが、これはまさにJITです。 言い換えれば、私たちのチームの20人がDmitryより悪くないJITを理解し始めても、これはJITの性質の複雑さを変えません。



PHPの開発は遅くなりますか?



そう考える理由はありません。 十分な時間があるので、PHP 8の準備が整う頃には、バグの修正やPHPの開発に関しては、今日と同じくらい効率的に動作するのに十分なJITをマスターした人が十分にいると言えます。



これをJITの元の複雑さの考えに関連付けようとするとき、新しい機能の導入に費やす時間のほとんどはそれらの議論に費やされることを忘れないでください。 ほとんどの場合、機能に取り組んでバグを修正するとき、コードの記述には数分または数時間かかり、議論には数週間または数か月かかります。 まれに、コードを数時間または数日間記述する必要がありますが、それでも議論は常に長続きします。



私が言いたかったのはそれだけです。



そして、生産性について話しているので、同僚のPavel Murzakovを5月17日のPHPロシア会議のレポートに招待します。 Pashaは、PHPコードから最後のCPU秒を圧縮する方法を知っています!



All Articles