Contact salesFree trial
Blog

PHP 8.0-Funktionen im Fokus: Just-in-Time-Kompilierung

PHPKonfigurationLeistung
30 Oktober 2020
Teilen Sie

Einige Hintergrundinformationen

Computer verstehen eigentlich keine Programmiersprachen, sondern sehr einfache Anweisungen, die kein Mensch von Hand schreiben könnte. Es gibt viele Wege, um von einer menschenlesbaren Sprache wie PHP oder Rust zu einem für Computer verständlichen Satz von Anweisungen zu gelangen.

Die einfachste und in der Regel auch leistungsfähigste Methode besteht darin, den menschenfreundlichen Quellcode direkt in CPU-Anweisungen "Ahead-of-Time" (AOT) zu kompilieren. Diese Anweisungen werden dann in einer "binären", eigenständig ausführbaren Datei gespeichert. Zu den gängigen Sprachen, die diesen Ansatz verfolgen, gehören C, C++ und Rust.

Die am wenigsten leistungsfähige, aber in der Regel am einfachsten zu schreibende Übersetzungsmethode sind interpretierte Sprachen, die oft als "Skriptsprachen" bezeichnet werden. In diesem Fall gibt es ein "Interpreter"-Programm, das jede Anweisung des Quellcodes in Maschinencode übersetzt, während sie ausgeführt wird. PHP 3 arbeitete auf diese Weise, weshalb PHP 3 im Vergleich zu modernem PHP so erstaunlich langsam war.

Ein anderer Ansatz ist die Verwendung einer "virtuellen Maschine". Eine virtuelle Maschine arbeitet ähnlich wie ein Interpreter, aber sie wandelt den Quellcode zunächst in eine einfachere Sprache um, im Wesentlichen eine sehr einfache Skriptsprache, die dann viel schneller interpretiert werden kann. Dieser Ansatz ist heutzutage sehr beliebt, da er ein gutes Gleichgewicht zwischen Komplexität, einfacher Entwicklung und Leistung bietet. Manchmal erfolgt diese Konvertierung in eine "einfachere Sprache" im Voraus - wie bei Java, C# oder Go - und manchmal geschieht sie während des Betriebs - wie bei PHP, Python oder Javascript. Java nennt diese vereinfachte Version "Bytecode". PHP verwendet den Begriff "Opcodes". Die Idee ist dieselbe.

Genau zur rechten Zeit

Der neueste Trend bei der Kompilierung ist die Einführung eines "Just in Time"-Compilers, kurz JIT. Ein PHP-JIT-Compiler beginnt mit der vereinfachten Zwischensprache, und anstatt sie zu interpretieren, konvertiert er sie on-the-fly in Maschinencode, speichert diesen Maschinencode im Speicher und führt ihn aus.

PHP JIT-Compiler sind sehr trickreich, denn um eine gute Leistung zu erzielen, muss man im Allgemeinen selektiv vorgehen, welche Teile der Zwischensprache in Maschinencode kompiliert werden und welche nicht. Es ist nicht immer schneller, in Maschinencode zu konvertieren, je nach den spezifischen Details des Codes und der betreffenden Sprache. Außerdem kann der Prozess der Umwandlung des vereinfachten Codes in nativen Maschinencode länger dauern, als wenn man den vereinfachten Code nur einmal ausführt und damit fertig ist.

Aus diesem Grund analysieren die meisten PHP-JIT-Compiler den Code, während er ausgeführt wird, um zu ermitteln, welche Teile das beste Preis-Leistungs-Verhältnis bieten, und kompilieren dann nur diese Teile. Das theoretische Ergebnis ist, dass das Programm buchstäblich schneller wird, während es läuft und der PHP JIT-Compiler in der virtuellen Maschine lernt, welche Teile des Codes optimiert werden müssen.

Java war die erste weit verbreitete Sprache, die einen JIT in ihre virtuelle Maschine integriert hat. Die meisten großen Javascript-Engines tun dies jetzt auch. Und seit PHP 8.0 ist auch PHP in diese Liste aufgenommen worden.

Das PHP JIT

Das neue JIT von PHP hat lange auf sich warten lassen. Es befindet sich bereits seit mehreren Jahren in der Entwicklung und wurde in einer früheren Form in PHP 7.4 fast schon ausgeliefert. Die Arbeit daran, PHP JIT-fähig zu machen, war der Anstoß, der zu der umfassenden Überarbeitung der Engine führte, die 7.0 den massiven Leistungsschub bescherte.

Das PHP JIT ist als Erweiterung des Opcode-Caches aufgebaut. Das bedeutet, dass er entweder bei der Erstellung von PHP selbst oder zur Laufzeit über die php.ini aktiviert und deaktiviert werden kann.

Wie man es konfiguriert

Die JIT-Erweiterung ist standardmäßig deaktiviert. Sie kann in der php.ini aktiviert werden, indem opcache.jit_buffer_size auf einen Wert ungleich Null gesetzt wird. Damit wird gesteuert, wie viel Speicherplatz das JIT mit seinem optimierten Maschinencode füllen kann. Mehr ist jedoch nicht immer besser, da das JIT auch Zeit mit der Kompilierung von Code verschwenden kann, der nicht wirklich von der Kompilierung profitiert.

Die andere wichtige Einstellung ist opcache.jit, die vier Stufen der JIT-Aggressivität steuert. Diese Stufen werden als 4-stellige Zahlen dargestellt, obwohl es sich eigentlich nicht um numerische Werte, sondern um vier verschiedene Aggressivitätsstufen handelt. Der RFC und die Dokumentation enthalten weitere Details, so dass wir hier nicht näher darauf eingehen werden.

Es gibt keine allgemeingültige beste Konfiguration für den JIT. Wie so oft bei solchen fortschrittlichen Tools müssen Sie mit Ihrer eigenen Anwendung experimentieren und sie entsprechend anpassen.

Wird es helfen?

Aber wird das JIT die Leistung verbessern? Die vorhersehbare Antwort lautet wie immer "es kommt darauf an". Bei Webanwendungen vielleicht ein bisschen. Für PHP als Ökosystem: immens.

PHP ist so konzipiert, dass es in der Regel in einer Shared-Nothing-Konfiguration läuft. Nachdem jede Anfrage bearbeitet wurde, wird das Programm vollständig beendet. Das gibt dem JIT sehr wenig Zeit, den Code zu analysieren und zu optimieren, zumal der meiste Code in einer typischen Webanforderung nur einmal ausgeführt wird, da die Anforderung linear verarbeitet wird. Außerdem besteht der größte Teil dieser Anwendungen oft aus E/A (vor allem mit der Datenbank), und dabei kann das JIT überhaupt nicht helfen. Die bisher veröffentlichten Benchmarks zeigen, dass das JIT bei typischen PHP-Anwendungen, die über PHP-FPM oder Apacheausgeführt werden, nur einen marginalen Leistungszuwachs bringt .

Wo das JIT wirklich hilfreich sein kann, ist in Anwendungsfällen, in denen PHP heute oft nicht berücksichtigt wird. Persistente Daemons, Parser, maschinelles Lernen und andere langlaufende CPU-intensive Prozesse sind die wahren Vorteile. Ähnlich wie bei der in PHP 7.4 hinzugefügten Unterstützung für Foreign Function Interface (FFI) besteht das Ziel hier darin, PHP von einer erstklassigen Websprache zu einer erstklassigen allgemeinen Serversprache zu machen.

PHP-Parser ist "ein in PHP geschriebener PHP-Parser". Er stammt von demselben Nikita Popov, den wir in dieser Serie bereits erwähnt haben, und wird von vielen statischen Analysetools auf dem Markt verwendet, wie z.B. PHPStan. Nikita hat berichtet, dass PHP-Parser mit der neuen JIT-Engine in einigen Fällen sogar doppelt so schnell läuft.

Persistente Anwendungen wie React PHP oder AmPHP werden wahrscheinlich auch eine bemerkenswerte Verbesserung erfahren, wenn auch nicht ganz so stark, da sie eine vergleichsweise höhere I/O Abhänigkeit haben (wo die JIT nicht hilfreich ist).

Es gibt auch Bibliotheken für maschinelles Lernen für PHP, wie Rubix ML oder PHP-ML. Sie sind nicht so weit verbreitet wie ihre Python-Äquivalente, was zum Teil daran liegt, dass sie, da sie interpretiert werden, tendenziell langsamer sind als die C-Bibliotheken mit schönen Python-Wrappern. Mit einem JIT können diese CPU-intensiven Aufgaben jedoch genauso schnell oder sogar noch schneller sein als die in anderen Sprachen verfügbaren.

PHP ist nicht mehr nur die schnellste der großen Web-Skriptsprachen. Es ist jetzt eine brauchbare Hochleistungssprache für die allgemeine Datenverarbeitung, die persistente Worker, maschinelles Lernen und andere Aufgaben mit hoher CPU-Leistung in die Hände von Millionen von PHP-Entwicklern in aller Welt legt.

Wir müssen vor allem Dmitry Stogov und Zeev Suraski für die mehrjährigen Bemühungen danken, diesen RFC zustande zu bringen.

Ihr größtes Werk
steht vor der Tür

Kostenloser Test
Discord
© 2025 Platform.sh. All rights reserved.