Ausblick auf PHP 8: Teil 7

PHP 8.0-Features im Fokus: Der Just-in-Time Compiler
Keine Kommentare

Das Release von PHP 8 steht kurz bevor und mit ihm eine Reihe von Verbesserungen, neuen Funktionen und die generelle Überarbeitung, um die weit verbreitete serverseitige Websprache noch besser zu machen. In dieser Serie wollen wir darauf eingehen, was Sie über PHP 8 wissen sollten.

Der Countdown zum großen Release von PHP 8 ist bereits angebrochen. Die lang erwartete neue Version enthält eine ganze Reihe von neuen Funktionen und Verbesserungen, die den Entwicklern das Leben leichter machen sollen. In dieser Serie werfen wir einen Blick auf diese Neuerungen und was sie für die Nutzer bedeuten.

Beim letzten Mal haben wir uns mit den strengeren Regeln von PHP 8.0 befasst. Heute schauen wir uns an, wie die neue Version schneller werden soll.

Hintergrund

Computer verstehen eigentlich keine Programmiersprachen, sie verstehen lediglich Anweisungen, die kein Mensch von Hand schreiben könnte. Es gibt viele Wege, um von einer menschenlesbaren Sprache wie PHP oder Rust zu einem computerverständlichen Befehl zu gelangen.

Die einfachste und in der Regel performanteste Methode ist, den menschenfreundlichen Quellcode direkt in CPU-Anweisungen „Ahead-of-Time“ (AOT) zu kompilieren. Diese Anweisungen werden dann in einer „binären“ eigenständigen ausführbaren Datei gespeichert. Einige verbreitete Sprachen, die diesen Ansatz verfolgen, sind C, C++ und Rust. Die am wenigsten performante, aber normalerweise 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, wenn er „ausgeführt“ wird. PHP 3 funktionierte auf diese Weise, weshalb diese Version im Vergleich zu modernem PHP so erstaunlich langsam war.

Ein anderer Ansatz ist die Verwendung einer „virtuellen Maschine“. Eine virtuelle Maschine arbeitet auf ähnliche Weise wie ein Interpreter, wandelt aber zunächst den Quellcode in eine einfachere Sprache um – eine sehr niedrige Skriptsprache, welche 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 die Konvertierung in eine „einfachere Sprache“ Ahead-of-Time – wie in Java, C# oder Go- und manchmal geschieht sie On-the-Fly, wie in PHP, Python oder Javascript. Java nennt diese vereinfachte Version „Bytecode“. PHP verwendet den Begriff „Opcodes“. Beides meint das Gleiche.

IT Security Camp im Februar 2021

Mit Christian Schneider

Christian ist als freiberuflicher Whitehat Hacker, Trainer und Security-Coach tätig. Als Softwareentwickler mit mittlerweile 20 Jahren Erfahrung fand er 2005 seinen Themenschwerpunkt im Bereich IT-Security.

Interview mit Christian Schneider zum Thema „DevSecOps“.

DevSecOps ist, bezogen auf Security-Checks, die logische Fortführung der Automatisierung im DevOps-Sinne

Just-in-Time

Der neueste Trend in der Kompilierung ist die Einführung eines „Just-in-Time“-Kompilers, oder JIT. Ein JIT-Compiler beginnt mit der vereinfachten Zwischensprache, und anstatt sie zu interpretieren, wandelt er sie On-the-Fly in Maschinencode um, speichert und führt ihn aus. JIT-Compiler sind sehr tückisch, denn um eine gute Leistung aus ihnen herauszuholen, muss man in der Regel auswählen, welche Teile der Sprache zu 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. Darüber hinaus kann der Prozess der Konvertierung des vereinfachten Codes in nativen Maschinencode länger dauern, als wenn dieser nur einmal ausgeführt und fertig gestellt wird.

Aus diesem Grund analysieren die meisten JIT-Compiler den Code während der Ausführung, um zu ermitteln, welche Teile am meisten Sinn ergeben würden, und kompilieren dann genau diese Bits. Das theoretische Ergebnis ist, dass das Programm buchstäblich schneller wird, während es läuft und der JIT-Compiler in der virtuellen Maschine lernt, welche Teile des Codes noch optimiert werden müssen. Java war die erste weit verbreitete Sprache, die eine JIT in ihre virtuelle Maschine integrierte. Die meisten großen Javascript-Engines tun dies heute ebenfalls. Mit der Version 8.0 wird sich PHP dieser Liste anschließen.

Der PHP JIT

Der neue JIT von PHP hat lange auf sich warten lassen. Tatsächlich befindet er sich bereits seit mehreren Jahren in der Entwicklung und wurde in einer früheren Form bereits beinahe in PHP 7.4 veröffentlicht. Die Arbeit daran, PHP JIT-fähig zu machen, war der Anstoß, der zu der umfassenden Überarbeitung der Engine führte, die 7.0 seine massive Leistungssteigerung ermöglichte.

PHP JIT ist als eine Erweiterung des Opcode-Caches konzipiert. Das bedeutet, dass es entweder beim Erstellen von PHP selbst oder zur Laufzeit über php.ini aktiviert und deaktiviert werden kann.

Die richtige Konfiguration

Die JIT-Erweiterung ist standardmäßig deaktiviert. Dies kann in php.ini geändert werden, indem opcache.jit_buffer_size auf einen Wert ungleich Null gesetzt wird. Das steuert, wie viel Platz im Speicher der JIT mit ihrem optimierten Maschinencode füllen kann. Mehr ist jedoch nicht immer besser, da der JIT auch Zeit mit der Kompilierung von Code verschwenden könnte, der nicht wirklich davon profitiert, kompiliert zu werden. Die andere wichtige Einstellung ist opcache.jit, das vier Stufen der JIT-Aktivität steuert. Diese Stufen werden als 4-stellige Zahlen dargestellt, obwohl es sich eigentlich nicht um numerische Werte, sondern um vier verschiedene Stufen handelt. Der RFC und die Dokumentation enthalten alle weiteren Einzelheiten, so dass wir hier nicht ins Detail gehen müssen.
Es gibt keine allgemein beste Konfiguration für den JIT. Wie es bei fortgeschrittenen Werkzeugen wie diesem oft der Fall ist, müssen Sie mit Ihrer eigenen Anwendung experimentieren und sie entsprechend abstimmen.

Was bringt der JIT?

Aber wird der JIT die Leistung verbessern? Die vorhersehbare Antwort lautet wie immer „es kommt darauf an“. Bei Webanwendungen vielleicht irgendwie. Für PHP als Ökosystem, immens. PHP läuft vom Design her normalerweise in einer Konfiguration, in der nichts gemeinsam genutzt wird. Nachdem jede Anfrage bearbeitet wurde, wird das Programm vollständig beendet. Das gibt der JIT sehr wenig Zeit, um Code zu analysieren und zu optimieren, zumal der meiste Code in einem typischen Web Request nur einmal ausgeführt wird, da die Anforderung linear behandelt wird. Außerdem handelt es sich bei dem größten Teil dieser Anwendungen oft um I/O (hauptsächlich Kommunikation mit der Datenbank), und der JIT kann dabei überhaupt nicht helfen. Die bisher veröffentlichten Benchmarks zeigen, dass der JIT bei typischen PHP-Anwendungen, die über PHP-FPM oder Apache laufen, nur eine marginale Leistungssteigerung bietet.

Wo das JIT das Potential hat, wirklich hilfreich zu sein, ist in Anwendungsfällen, in denen PHP heute oft nicht in Betracht gezogen wird. Persistente Daemons, Parser, Machine Learning und andere lang laufende CPU-intensive Prozesse sind die Bereiche, in denen die wirklichen Vorteile liegen. Ähnlich wie bei der Unterstützung des Foreign Function Interface (FFI) (Teil 1, Teil 2, Teil 3), die zu PHP 7.4 hinzugefügt wurde, besteht das Ziel hier darin, PHP den Durchbruch von einer erstklassigen Websprache zu einer erstklassigen allgemeinen Serversprache zu ermöglichen.

PHP-Parser ist „ein in PHP geschriebener PHP-Parser“. Er stammt von dem gleichen Nikita Popov, den wir in dieser Reihe bereits öfters erwähnt haben, und wird von vielen statischen Analysetools auf dem heutigen Markt verwendet, wie z.B. PHPStan. Laut Nikita Popov läuft der PHP-Parser mit der neuen JIT-Engine in einigen Fällen doppelt so schnell.

Persistente Anwendungen wie React PHP oder AmPHP werden wahrscheinlich ebenfalls eine bemerkenswerte Verbesserung erfahren, wenn auch nicht ganz so viel, da sie dazu neigen, eine Menge I/O durchzuführen (wobei der JIT nicht hilfreich ist). Es gibt Libraries 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, wenn sie interpretiert werden, dazu neigen, langsamer zu sein als die C-Libraries mit netten Python-Wrappern. Mit einem JIT können diese CPU-intensiven Aufgaben jedoch am Ende genauso schnell oder möglicherweise sogar 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 lebensfähige, hochleistungsfähige allgemeine Datenverarbeitungssprache, die Millionen von PHP-Entwicklern auf der ganzen Welt hartnäckige Mitarbeiter, maschinelles Lernen und andere Aufgaben mit hohem CPU-Aufwand in die Hände gibt.

Wir haben in erster Linie Dmitry Stogov und Zeev Suraski für die mehrjährigen Bemühungen zu danken, die diesen RFC verwirklichten.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Abonnieren
Benachrichtige mich bei
guest
0 Comments
Inline Feedbacks
View all comments
X
- Gib Deinen Standort ein -
- or -