コンパむラ、むンタヌプリタヌ、およびJITの抂芁

PHP 7の誕生によっお、抜象的な構文ツリヌ、ゞャストむンタむムコンパむラ、静的分析などに関する議論は終わりたせんが、これらすべおの甚語はどういう意味ですか これらは、PHPの生産性を高める魔法の特性ですか もしそうなら、それはどのようにすべお機胜したすか この蚘事では、プログラミング蚀語がどのように機胜するかの基本を調べ、PHPスクリプトなど、コンピュヌタヌが起動する前に完了する必芁のあるプロセスに぀いお説明したす。



コヌドの解釈



しかし、これがすべおどのように機胜するかに぀いお話す前に、1぀の簡単な䟋を芋おみたしょう。 新しいプログラミング蚀語があるこずを想像しおみおください名前は䜕であれ。 蚀語は非垞にシンプルです





䟋



set a 1





set b 2





add abc





print c







これは単玔な蚀語なので、このコヌドは画面3にのみ衚瀺されるず安党に想定できたす。set挔算子は倉数を受け取り、それに番号を割り圓おたすPHPの$a=1



ように。 add



ステヌトメントは、远加する2぀の倉数を取り、3番目の倉数に結果を保存したす。 print



ステヌトメントはそれを衚瀺したす。



次に、各「匏」を読み取り、挔算子ずオペランドを芋぀けお、特定の挔算子に応じおそれらを䜿甚しお䜕かを実行するプログラムを䜜成したしょう。 リスト1を芋るずわかるように、これはPHPでの実装は非垞に簡単です。



リスト1



 01. <?php 02. 03. $lines = file($argv[1]); 04. 05. $linenr = 0; 06. foreach ($lines as $line) { 07. $linenr++; 08. $operands = explode(" ", trim($line)); 09. $command = array_shift($operands); 10. 11. switch ($command) { 12. case 'set' : 13. $vars[$operands[0]] = $operands[1]; 14. break; 15. case 'add' : 16. $vars[$operands[2]] = $vars[$operands[0]] + $vars[$operands[1]]; 17. break; 18. case 'print' : 19. print $vars[$operands[0]] . "\n"; 20. break; 21. default : 22. throw new Exception(sprintf("Unknown command in line %s\n", $linenr)); 23. } 24. }
      
      





これは非垞にシンプルなプログラムであり、新しい蚀語で次のWebアプリケヌションを䜜成する必芁はありたせん。 しかし、この䟋は、新しい蚀語を䜜成し、この蚀語を読み取っお実行できるプログラムを取埗するこずがいかに簡単かを理解するのに圹立ちたす。 この堎合、゜ヌスファむルを1行ず぀読み取り、珟圚の挔算子に応じおコヌドを実行したす。 アプリケヌションを実行するために、アセンブラヌたたはバむナリコヌドに倉換する必芁はありたせん。既にうたく機胜しおいたす。 プログラムを実行するこの方法は、解釈ず呌ばれたす。 たずえば、基本プログラムは倚くの堎合、この方法で実行されたす。各匏が読み取られ、すぐに高レベルモヌドで実行されたす。



しかし、倚くの問題がありたす。 それらの1぀は、同様の蚀語プロセッサの䜜成は非垞に簡単ですが、新しい蚀語は非垞にゆっくり実行されるこずです。 結局、各行を凊理し、チェックする必芁がありたす





しかし、他のタスクを忘れおはなりたせん。 たずえば、setステヌトメントは倉数のみ数倀たたは文字列倀を割り圓おるこずができたすか たたは、他の倉数の倀も 各匏を適切に凊理するには、これらすべおの質問に答える必芁がありたす。 set 1



4を曞き蟌むずどうなりたすか ぀たり、この方法では、高速実行アプリケヌションを䜜成するこずはほずんど䞍可胜です。



しかし、そのゆずりにかかわらず、解釈には利点がありたす。倉曎のたびにプログラムをすぐに実行できたす。 泚意PHPスクリプトで䜕かを倉曎するず、すぐに実行しお倉曎を確認できたす。 これは、PHPがむンタヌプリタヌ蚀語であるこずを意味したすか 珟時点では、はいず仮定したす。 PHPスクリプトは、仮想の単玔な蚀語のように解釈されたす。 しかし、次のセクションでは、これに戻りたす



トランスコンパむル



プログラムを「高速」にするにはどうすればよいですか これはさたざたな方法で実行できたす。 Facebookで開発されたそのうちの1぀はHipHopず呌ばれたす珟圚䜿甚されおいるHHVMではなく、「叀い」HipHopシステムを意味したす。 HipHopは、ある蚀語PHPを別の蚀語C ++に倉換したした。 倉換結果は、C ++コンパむラを䜿甚しおバむナリコヌドに倉換できたす。 圌のコンピュヌタヌは、むンタヌプリタヌの圢で远加の負荷なしに理解しお実行するこずができたす。 その結果、膚倧な量のコンピュヌティングリ゜ヌスが節玄され、アプリケヌションの実行速床が倧幅に向䞊したす。



この方法は、゜ヌスから゜ヌスぞのコンパむル、トランスコンパむル、たたはトランスコンパむルずも呌ばれたす。 実際には、バむナリコヌドぞのコンパむルではなく、既存のコンパむラによっおマシンコヌドにコンパむルできるものぞの倉換です。



トランスコンパむルを䜿甚するず、バむナリコヌドを盎接実行できるため、パフォヌマンスが向䞊したす。 ただし、このメ゜ッドには欠点がありたす。コヌドを実行する前に、最初にトランスコンパむルを行い、次に実際のコンパむルを行う必芁がありたす。 ただし、これはアプリケヌションに倉曎が加えられた堎合、぀たり開発䞭にのみ行う必芁がありたす。



トランスコンパむルは、ハヌド蚀語をより単玔か぀動的にするためにも䜿甚されたす。 たずえば、ブラりザはLESS、SASS、SCSSで蚘述されたコヌドを理解したせん。 しかし、その埌、ブラりザが理解できるCSSに眮き換えるこずができたす。 CSSは保守が簡単ですが、远加でトランスコンパむルする必芁がありたす。



線集



すべおがさらに速く動䜜するためには、トランスコンパむルの段階を取り陀く必芁がありたす。 ぀たり、私たちの蚀語をすぐにバむナリコヌドにコンパむルし、解釈やトランスコンパむルの圢で远加の負荷をかけずにすぐに実行できたす。



残念ながら、コンパむラを曞くこずは、コンピュヌタヌサむ゚ンスで最も難しいタスクの1぀です。 たずえば、バむナリコヌドにコンパむルする堎合、32ビットLinux、64ビットWindows、たたは䞀般的なOS Xで実行するコンピュヌタヌを怜蚎する必芁がありたすが、解釈されたスクリプトはどこでも簡単に実行できたす。 PHPのように、スクリプトがどこで実行されるかを心配する必芁はありたせん。 特定のOS向けのコヌドが存圚する堎合がありたすが、他のシステムでスクリプトを実行するこずはできたせんが、これはむンタヌプリタヌの問題ではありたせん。



しかし、トランスコンパむルの段階をなくしおも、コンパむルから逃げるこずはできたせん。 たずえば、Cコンパむルされた蚀語で曞かれた倧きなプログラムは、ほが1時間コンパむルできたす。 PHPでアプリケヌションを䜜成し、倉曎が機胜するかどうかを確認するたでさらに10分埅぀必芁があるず想像しおください。



最善を尜くしお



解釈の実行に時間がかかり、コンパむルが実装が難しく、開発に時間がかかる堎合、PHP、Python、Rubyなどの蚀語はどのように機胜したすか 圌らはかなり速いです



これは、解釈ずコンパむルの䞡方を䜿甚するためです。 それがどうなるか芋おみたしょう。



架空の蚀語をバむナリコヌドに盎接倉換するのではなく、それに非垞によく䌌たもの「バむトコヌド」ず呌ばれるに倉換できるずしたらどうでしょうか。 このバむトコヌドがコンピュヌタヌの動䜜に非垞に近い堎合、その解釈は非垞に高速になりたすたずえば、1秒あたり数癟䞇のバむトコヌド。 これにより、アプリケヌションはコンパむルされたものずほが同じ速床になり、むンタヌプリタヌ蚀語のすべおの利点が保持されたす。 最も重芁なこずは、倉曎ごずにスクリプトをコンパむルする必芁がないこずです。



ずおも魅力的です。 実際、倚くの蚀語は同様の方法で動䜜したす-PHP、Ruby、Python、さらにはJava。 ゜ヌスコヌドの行を順番に読み取っお解釈する代わりに、これらの蚀語は異なるアプロヌチを䜿甚したす。





実際、さらに倚くのステップがあり、実際にはプロセス党䜓がはるかに耇雑です。 ただし、䞀般に、説明されおいる3぀の手順は、コマンドラむンからスクリプトを実行するか、Webサヌバヌを介しお芁求を実行するのに十分です。



プロセスは簡単に最適化できたす。Webサヌバヌを起動し、各リク゚ストがindex.php



スクリプトを実行するずしたす。 メモリに毎回ロヌドするのはなぜですか リク゚ストごずにすばやく倉換できるように、ファむルをキャッシュするこずをお勧めしたす。



別の最適化バむトコヌドを生成した埌、埌続のすべおのリク゚ストに䜿甚できたす。 したがっお、それもキャッシュできたす最も重芁なこずは、゜ヌスファむルが倉曎されたずきに、バむトコヌドが再コンパむルされるこずを確認しおください。 これは、PHPのOPCache拡匵機胜のように、オペコヌドキャッシュが行うこずずたったく同じです。コンパむルされたスクリプトは、過剰なダりンロヌドやバむトコヌドぞのコンパむルなしに埌続のリク゚ストですばやく実行できるようにキャッシュされたす。



最埌に、高速化の最埌のステップは、PHPむンタヌプリタヌによるバむトコヌドの実行です。 次のパヌトでは、これを埓来の通蚳者ず比范したす。 混乱を避けるため、このようなバむトコヌドむンタヌプリタヌは、「仮想マシン」ず呌ばれたす。これは、ある皋床たでマシンコンピュヌタヌの䜜業をコピヌするためです。 これを、VirtualBoxやVMwareなどのコンピュヌタヌで実行されおいる仮想マシンず混同しないでください。 これは、Javaの䞖界のJVMJava仮想マシンやPHPの䞖界のHHVMHipHop仮想マシンのようなものです。 PythonずRubyには独自の仮想マシンがありたす。 ある意味では、これらはすべお非垞に専門的で生産的なバむトコヌドむンタヌプリタヌです。



各VMは、特定の蚀語によっお生成された独自のバむトコヌドを実行したすが、互いに互換性がありたせん。 Python VMでPHPバむトコヌドを実行するこずはできたせん。逆の堎合も同様です。 ただし、PHPスクリプトをバむトコヌドにコンパむルするプログラムを䜜成するこずは理論的には可胜であり、これはPython VMによっお理解されたす。 したがっお、理論的には、PythonでPHPスクリプトを実行できたす深刻な課題です。



バむトコヌド



バむトコヌドはどのように芋え、動䜜したすか 2぀の䟋を芋おみたしょう。 PHPコヌドを取埗したす。



 $a = 3; echo "hello world"; print $a + 1;
      
      





3v4l.orgを䜿甚するか、VLD拡匵機胜をむンストヌルするこずにより、そのバむトコヌドを衚瀺できたす。 次のものが埗られたす。







次に、同様のPythonの䟋を取り䞊げたす。



 def foobar(): a = 1 print "hello world", print a + 4
      
      





Pythonはオペコヌドを盎接生成できたす©python



dis.disfunc 







2぀の単玔なスクリプトずそのバむトコヌドがありたす。 バむトコヌドは、蚘事の冒頭で「䜜成」した蚀語に䌌おいるこずに泚意しおください。各行は、任意の数のオペランドを持぀挔算子です。 PHPバむトコヌドでは、接頭蟞が倉数に远加されたすしたがっお、0は倉数0を意味したす。$ a倉数を䜿甚するこずは重芁ではありたせん。コンパむル䞭、倉数名は倀を倱い、数倀に倉換されたす。 これにより、仮想マシンによる凊理が促進および加速されたす。 必芁な「チェック」のほずんどはコンパむル段階で実行されたす。これにより、仮想マシンから負荷が取り陀かれ、速床が向䞊したす。



バむトコヌドは単玔な呜什で構成されおいるため、解釈は非垞に高速です。 むンタプリタ蚀語の各匏で凊理する必芁がある数千のバむナリ呜什の代わりに、各匏のバむトコヌドには数癟の呜什がありたすさらに少ない堎合もありたす。 したがっお、仮想マシンはむンタヌプリタヌ蚀語よりもはるかに高速に実行されたす。



蚀い換えれば、仮想女性は2぀の䞖界のすべおを最倧限に掻甚したした。 ゜ヌスからバむトコヌドにコンパむルする必芁がありたすが、このプロセスは高速で透過的です。 そしお、バむトコヌドを受信した埌、仮想マシンは䞍必芁なオヌバヌヘッドなしに迅速か぀効率的にそれを解釈したす。 その結果、高性胜のアプリケヌションができたした。



゜ヌスからバむトコヌドぞ



生成されたバむトコヌドを効率的に実行できるようになったので、゜ヌスコヌドをそのバむトコヌドにコンパむルするタスクは残りたす。



次のPHP匏を怜蚎しおください。



 $a = 1; $a=1; $a = 1;
      
      





それらはすべお等しく圓おはたり、同じバむトコヌドに倉換する必芁がありたす。 しかし、それらをどのように読みたすか 実際、独自のむンタヌプリタヌでは、コマンドを解析し、スペヌスで区切りたす。 ぀たり、むンデントやスペヌス、1行でブラケット、2行で折り返しなどを䜿甚できるPHPずは異なり、プログラマヌはコヌドを同じスタむルで蚘述する必芁がありたす。たず、コンパむラヌは゜ヌスを倉換しようずしたすトヌクン内のコヌド。 このプロセスは、字句解析たたはトヌクン化ず呌ばれたす。



レキシン



トヌクン化字句解析は、゜ヌスPHPコヌドを-その意味を理解せずに-トヌクンの長いリストに倉換するこずで構成されたす。 これは耇雑なプロセスですが、PHPでは同様のこずが非垞に簡単に行えたす。 リスト2のコヌドは次の結果を生成したす。



 T_OPEN_TAG <?php T_VARIABLE $a T_WHITESPACE = T_WHITESPACE T_LNUMBER 3 ; T_WHITESPACE T_ECHO echo T_WHITESPACE T_CONSTANT_ENCAPSED_STRING "hello world" ;
      
      





文字列倀はトヌクンに倉換されたす





トヌクナむザヌは、コヌドを読み取るずきに、文字aが付いた$蚘号を怜出するず、これを認識したす。その埌、任意の数の文字ず数字を続けるこずができたす。 番号はT_LNUMBERずしおトヌクン化され、1ビット以䞊にするこずができたす。 トヌクン化により、プログラマヌに匷制するこずなく、より構造化された圢匏で゜ヌスコヌドを提瀺できたす。 しかし、すでに述べたように、トヌクナむザヌはトヌクンの意味を理解しおいたせん。 理想的には、$ a = 1ず1 = $ aの䞡方をトヌクン化したす。 次のパヌトでは、解析方法を孊習したす-倀をトヌクンのストリヌムに蚭定したす。



解析



トヌクンを解析するずき、蚀語を構成するいく぀かの「ルヌル」に埓う必芁がありたす。 たずえば、ルヌルがある堎合がありたす。プログラムで最初に怜出されたトヌクンはT_OPEN_TAG<Phpに察応でなければなりたせん。



別の可胜なルヌル割り圓おは、任意のT_VARIABLEの埌に=文字、次にT_LNUMBER、T_VARIABLE、たたはT_CONSTANT_ENCAPSED_STRINGを含めるこずができたす。 ぀たり、$ a = 1、たたは$ a = $ b、たたは$ a = 'foobar'を蚱可したすが、1 = $ aは蚱可したせん。 パヌサヌが、どのルヌルも満たさない䞀連のトヌクンを怜出するず、構文゚ラヌが自動的に生成されたす。 䞀般に、解析は蚀語を定矩し、構文芏則を䜜成できるようにするプロセスです。



PHP で䜿甚されおいるルヌルのリストを参照しおください。 PHPスクリプトが構文芏則を満たしおいる堎合、構文が正しいだけでなく、意味があるこずを確認するために远加のチェックが実行されたす public abstract final final private class foo() {}



の定矩は正しいかもしれたせんが、芳点からは意味がありたせんPHP トヌクン化ず解析は扱いにくいプロセスであり、倚くの堎合、サヌドパヌティのアプリケヌションがそれらを実行するために䜿甚されたす。 しばしばflexやbisonなどのツヌルを䜿甚したすPHPでも。 たた、トランスコンパむラず芋なすこずもできたす。ルヌルをCコヌドに倉換し、PHPをコンパむルするず自動的にコンパむルされたす。



パヌサヌずトヌクナむザヌは他の分野で圹立ちたす。 たずえば、デヌタベヌス内のSQL匏を解析するために䜿甚され、倚くのパヌサヌずトヌクナむザヌもPHPで蚘述されおいたす。 Doctrineのオブゞェクトリレヌショナルマッパヌには、DQL匏甚の独自のパヌサヌず、DQLをSQLに倉換するための「トランスコンパむラヌ」がありたす。 Twigを含む倚くのテンプレヌト゚ンゞンは、独自のトヌクナむザヌずパヌサヌを䜿甚しお、テンプレヌトファむルをPHPスクリプトに「コンパむル」したす。 実際、これらの゚ンゞンはトランスコンパむラでもありたす



抜象構文ツリヌ



蚀語をトヌクン化しお解析した埌、バむトコヌドを生成できたす。 PHP 5.6たでは、解析䞭に生成されたした。 ただし、プロセスに別のステヌゞを远加するず、パヌサヌにバむトコヌドではなく、いわゆる抜象構文ツリヌASTを生成させるこずができたす。 これは、プログラム党䜓が抜象的に衚珟されるツリヌ構造です。 ASTは、バむトコヌドの生成を単玔化するだけでなく、倉換する前にツリヌを倉曎するこずもできたす。 ツリヌは垞に特別な方法で生成されたす。 ツリヌノヌドはif匏であり、必然的にその䞋に3぀の芁玠がありたす。





else



欠けおいる堎合でも、3぀の芁玠があり、3番目の芁玠だけが空になりたす。



その結果、プログラムをバむトコヌドに倉換する前に「曞き盎す」こずができたす。 これはコヌドを最適化するために時々䜿甚されたす。 開発者がルヌプ内で倉数を繰り返し再蚈算し、倉数の倀が垞に同じであるこずがわかっおいる堎合、オプティマむザヌはASTを曞き換えお、毎回再蚈算する必芁のない䞀時倉数を䜜成できたす。 ツリヌはコヌドの小さな再線成に䜿甚できるため、䞍芁になった倉数の削陀など、高速に動䜜したす。これは垞に可胜であるずは限りたせんが、プログラム党䜓のツリヌがある堎合、このようなチェックず最適化ははるかに簡単に実行できたす。 AST内では、倉数が䜿甚される前に宣蚀されおいるかどうか、たたは条件ブロックで割り圓おが䜿甚されおいるかどうかを確認できたす if ($a = 1) {}



。 たた、朜圚的に゚ラヌのある構造が怜出された堎合は、譊告を発行したす。 ツリヌを䜿甚しお、情報セキュリティの芳点からコヌドを分析し、スクリプトの実行䞭にナヌザヌに譊告するこずもできたす。



これは静的分析ず呌ばれたす。これにより、開発者が調和のずれた安党で高速なコヌドを䜜成するのに圹立぀新しい機胜、最適化、怜蚌システムを䜜成できたす。



PHP 7.0では、解析䞭にASTを生成する新しい解析゚ンゞンZend 3.0が導入されたした。 それは十分新鮮であるため、あたりそれを行うこずはできたせん。 しかし、その存圚の単なる事実は、近い将来にさたざたな機䌚の出珟を期埅できるこずを意味したす。 token_get_all()



関数は、文曞化されおいない新しい定数TOKEN_PARSEをすでに受け入れおいたす。これは将来、トヌクンだけでなく解析されたASTを返すために䜿甚できたす。 php-astなどのサヌドパヌティの拡匵機胜を䜿甚するず、PHPでツリヌを盎接衚瀺および線集できたす。 Zend゚ンゞンずAST実装の完党な再蚭蚈により、PHPはさたざたな新しい課題に盎面したす。



Jit



ASTから生成された高床に最適化されたバむトコヌドを実行する仮想マシンに加えお、速床を䞊げる別の手法がありたす。 しかし、これは実装が最も難しいものの1぀です。



アプリケヌションはどのように実行されおいたすか セットアップには倚くの時間がかかりたす。たずえば、フレヌムワヌクの起動、ルヌトの解析、環境倉数の凊理などが必芁です。これらの手順がすべお完了した埌、プログラムは通垞実行されおいたせん。 , - . , , (, ) ? , , , . , , , , .



. -, . JIT- (just-in-time, ). . , - , , . — . , . , .



JIT- . ; , ; , . JIT' : , .



JIT' , . JIT' runtime , . , JIT' .



HHVM, JIT-: PHP- ( Hack) -, HHVM. , ; , . -, .



PHP 7 JIT-, . , , JIT-. , PHP 7 !



All Articles