JIT ist eine Compiler-Strategie, die Code als Zwischenzustand ausdrückt, ihn zur Laufzeit in architekturabhängigen Maschinencode umwandelt und ihn im laufenden Betrieb ausführt. In PHP8 muss Zend VM nicht interpretiert werden und diese Anweisungen werden direkt als Anweisungen auf CPU-Ebene ausgeführt.
JIT für PHP 8
PHP 8 Just In Time (JIT) Compiler The Die Wirkung ist unbestreitbar. Bisher habe ich jedoch festgestellt, dass sehr wenig darüber bekannt ist, was JIT tun soll.
Empfohlenes Video-Tutorial: „PHP-Programmierung vom Anfänger bis zur Meisterschaft“
Nach vielen Recherchen und dem Verlassen habe ich beschlossen, den PHP-Quellcode selbst zu überprüfen. Durch die Kombination einiger meiner Kenntnisse der C-Sprache und aller Informationen, die ich bisher gesammelt habe, habe ich diesen Artikel verfasst, der Ihnen hoffentlich dabei helfen wird, PHPs JIT besser zu verstehen.
Um es einfach auszudrücken: Wenn die JIT wie erwartet funktioniert, wird Ihr Code nicht über die Zend-VM ausgeführt, sondern direkt als Satz von Anweisungen auf CPU-Ebene.
Das ist die ganze Idee.
Aber um es besser zu verstehen, müssen wir uns überlegen, wie PHP intern funktioniert. Nicht sehr kompliziert, bedarf aber einer Einführung.
Wie wird PHP-Code ausgeführt?
Wie wir alle wissen, ist PHP eine interpretierte Sprache, aber was bedeutet dieser Satz selbst?
Jedes Mal, wenn PHP-Code (Befehlszeilenskript oder WEB-Anwendung) ausgeführt wird, muss er den PHP-Interpreter durchlaufen. Am häufigsten werden die PHP-FPM- und CLI-Interpreter verwendet.
Die Aufgabe des Interpreters ist einfach: PHP-Code empfangen, interpretieren und das Ergebnis zurückgeben.
Allgemein interpretierte Sprachen folgen diesem Prozess. Bei einigen Sprachen entfallen möglicherweise einige Schritte, die Grundidee ist jedoch dieselbe. In PHP ist der Prozess wie folgt:
liest den PHP-Code und interpretiert ihn als eine Reihe von Schlüsselwörtern, sogenannte Tokens. Durch diesen Vorgang weiß der Interpreter, welcher Code in jedem Programm geschrieben wurde. Dieser Schritt wird Lexing oder Tokenizing genannt.
Nachdem der PHP-Interpreter die Token-Sammlung erhalten hat, versucht er, sie zu analysieren. Ein abstrakter Syntaxbaum (AST) wird durch einen Prozess namens Parsing generiert. Hier ist AST eine Reihe von Knoten, die darstellen, welche Operationen ausgeführt werden sollen. Beispielsweise bedeutet „echo 1 + 1“ tatsächlich „das Ergebnis von 1 + 1 drucken“ oder genauer gesagt „eine Operation drucken, diese Operation ist 1 + 1“.
Mit AST sind Abläufe und Prioritäten leichter zu verstehen. Um einen abstrakten Syntaxbaum in eine von der CPU ausführbare Operation umzuwandeln, ist ein Übergangsausdruck (IR) erforderlich, den wir in PHP Opcodes nennen. Der Prozess der Konvertierung von ASTs in Opcodes wird als Kompilierung bezeichnet.
Mit Opcodes kommt jetzt der spaßige Teil: Code ausführen! PHP verfügt über eine Engine namens Zend VM, die eine Folge von Opcodes empfangen und ausführen kann. Nachdem alle Opcodes ausgeführt wurden, beendet Zend VM das Programm.
Dies ist ein Flussdiagramm, das die Opcache-Erweiterung enthält:
Welche Auswirkungen hat die JIT-Kompilierung?
Nachdem ich mir Zeevs PHP- und JIT-Sendung auf PHP Internals News angehört hatte, fand ich heraus, was JIT eigentlich macht.
Wenn die Opcache-Erweiterung es schneller macht, Opcodes direkt an die Zend-VM zu übertragen, lässt das JIT sie laufen, ohne die Zend-VM zu verwenden.
Zend VM ist ein in C geschriebenes Programm, das als Schicht zwischen Opcodes und der CPU fungiert. JIT generiert kompilierten Code direkt zur Laufzeit, sodass PHP
die Zend-VM überspringen und direkt von der CPU ausgeführt werden kann. Theoretisch wird die Leistung besser sein.
Das klingt seltsam, da für jeden Strukturtyp eine konkrete Implementierung geschrieben werden muss, bevor er in Maschinencode kompiliert werden kann. Aber tatsächlich ist das vernünftig.
PHPs JIT verwendet eine Bibliothek namens DynASM (Dynamic Assembler), die einen Satz von CPU-Anweisungen in einem bestimmten Format in Assembler-Code für viele verschiedene CPU-Typen abbildet. Daher muss der Compiler nur DynASM verwenden, um Opcodes in Maschinencode für eine bestimmte Struktur umzuwandeln.
Allerdings gibt es ein Problem, das mich schon seit langem beschäftigt.
Wenn das Vorladen PHP-Code vor der Ausführung in Opcodes analysieren kann und DynASM Opcodes in Maschinencode kompilieren kann (Just-In-Time-Kompilierung), warum verwenden wir dann nicht sofort die Ahead-of-Time-Kompilierung?
Einer der Gründe, warum ich durch das Anhören von Zeevs Sendung herausgefunden habe, ist, dass PHP eine schwach typisierte Sprache ist, was bedeutet, dass PHP den Typ einer Variablen oft erst kennt, wenn die Zend-VM versucht, einen Opcode auszuführen .
Sie können den Union-Typ Zend_value anzeigen, um zu erfahren, dass viele Zeiger auf Variablen unterschiedlichen Typs verweisen. Immer wenn Zend VM versucht, einen Wert von einem Zend_value abzurufen, verwendet es ein Makro wie ZSTR_VAL, um einen Zeiger auf einen String im Union-Typ abzurufen.
Zum Beispiel verarbeitet dieser Zend VM-Handler „kleiner als oder gleich“ (
Die Verwendung von Maschinencode zur Ausführung der Typinferenzlogik ist nicht möglich und kann langsamer werden.
Erst auszuwerten und dann zu kompilieren ist ebenfalls keine gute Option, da das Kompilieren in Maschinencode eine CPU-intensive Aufgabe ist. Es ist also auch nicht gut, alles zur Laufzeit zu kompilieren.
Das obige ist der detaillierte Inhalt vonWas ist der JIT von PHP8?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!