Der PHP Opcode, der von der PHP-Engine generiert wird, ist stark von der Art und Weise beeinflusst, wie du dein Code schreibst, nicht nur hinsichtlich der Anzahl der Anweisungen, um eine Aufgabe zu erledigen. Klar hat das sehr viel Bedeutung und glaube, dass es für dich offensichtlich ist.
Was weniger offensichtlich sein könnte, ist dass selbst die Syntax des Codes den generierten Opcode völlig verändern kann, was der CPU der Maschine viel Overhead verursacht, um den exakt gleichen Code auszuführen.
In den letzten paar Jahren hat mein SaaS-Produkt sehr gewachsen und mir die Gelegenheit gegeben, immer tiefer in Optimierungsverfahren zu gehen, um meine Workload so effizient wie möglich abzuarbeiten.
Die Ergebnisse, die ich gesehen habe, sind beeindruckend und haben mir sehr geholfen, freies Cash Flow freizuschlagen, um meinen SaaS-Weg weiter zu entwickeln.
An dieser Stelle verarbeitet der PHP-Prozess in meinem SaaS-Produkt mehr als 1,2 Milliarden (mit „b“) Datenpakete pro Tag auf einer Maschine mit 2vCPU und 8GB Arbeitsspeicher. Ich verwende ein AWS-Autoskalierungs-Group, um mehr Flexibilität im Falle von unvorhersehbaren Spitzen zu haben, aber es fügt selten eine zweite Maschine hinzu (eine/zwei Mal die Woche).
Lass uns zum Thema des Artikels gehen. Ich glaube, du findest es sehr interessant.
Was ist PHP Opcode?
PHP Opcode steht für Operation Code, und es bezieht sich auf die niedrigeninstruktionen, die von der PHP-Engine nach der Kompilierung des von dir geschriebenen PHP-Quellcodes ausgeführt werden.
In PHP passiert die Kompilierung während der Laufzeit: Grundsätzlich wird der erste Mal, wenn dein Code von der PHP-Engine aufgenommen wird, in diesen maschinenfreundlichen Code kompiliert, cacht (also kompiliert die Engine nicht denselben Code erneut) und dann ausgeführt.
Dies ist eine einfache Darstellung des Prozesses:
PHP Opcode Caching
Das Cachen der PHP Opcodes ermöglicht es, drei Schritte in dem Prozess der Codeausführung zu sparen: die Parsing der Roh-PHP-Code, die Tokenisierung und die Kompilierung.
Sobald die Opcode zum ersten Mal generiert wurden, werden sie im Speicher gespeichert, sodass sie für spätere Anfragen wiederverwendet werden können. Dies reduziert die Notwendigkeit, dass der PHP-Motor den gleichen PHP-Code bei jeder Ausführung neu kompilieren muss, was einen erheblichen CPU- und Speicherverbrauch einschränkt.
Der am häufigsten verwendete Opcode-Cache in PHP ist OPCache, der ab PHP 5.5 standardmäßig bis zu den aktuellen Versionen enthalten ist. Er ist sehr effizient und weit verbreitet.
Das Cachen des vorkompilierten Skript-Bytecodes erfordert das Abweichen des Caches nach jeder Veröffentlichung. Dies liegt daran, dass, wenn geänderte Dateien die Bytecode-Version im Cache haben, PHP den alten Code bis zur Leere des Opcode-Caches aktiviert, sodass das neue Code erneut kompiliert wird und ein neues Cache-Element erzeugt wird.
Wie man PHP Opcode untersucht
Um zu verstehen, wie unterschiedliche Syntaxe Einfluss auf den Opcode des Skripts haben kann, müssen wir eine Methode finden, um den vom PHP-Motor generierten kompilierten Code zu erhalten.
Es gibt zwei Möglichkeiten, um den Opcode zu erhalten.
OPCache Native Funktionen
Wenn Sie die OPCache-Erweiterung auf Ihrem Rechner aktiviert haben, können Sie ihre native Funktionen verwenden, um den Opcode eines bestimmten PHP-Dateis zu erhalten:
// Force compilation of a script
opcache_compile_file(__DIR__.'/yourscript.php');
// Get OPcache status
$status = opcache_get_status();
// Inspect the script's entry in the cache
print_r($status['scripts'][__DIR__.'/yourscript.php']);
VLD (Vulcan Logic Disassembler) PHP-Erweiterung
VLD ist eine populäre PHP-Erweiterung, die kompilierte PHP-Code dekompiliert und die Opcodes ausgibt. Es ist ein leistungsstarkes Werkzeug zur Verstehen, wie PHP Ihren Code interpretiert und ausführt. Nach der Installation können Sie ein PHP-Skript mit VLD aktiviert mit dem Befehl php
mit den -d
Optionen ausführen:
php -d vld.active=1 -d vld.execute=0 yourscript.php
Der Output wird detaillierte Informationen über die kompilierten Opcodes enthalten, einschließlich jeder Operation, seiner zugehörigen Codezeile und mehr.
Verwenden Sie 3v4l (Akronym für EVAL)
3v4l ist eine sehr nützliche Online-Tool, das Ihnen erlaubt, die Opcode, die durch PHP-Code generiert werden, zu betrachten. Es ist im Grunde ein PHP-Server mit VLD installiert, der die VLD-Ausgabe erfasst und die Opcode im Browser anzeigt.
Bei seiner Freiheit nutzen wir dieses Online-Tool für die nächsten Analysen.
Wie man effiziente PHP-Opcode generiert
3v4l ist perfekt, um zu verstehen, wie die von uns verwendete Code-Syntax die resultierenden PHP-Opcode in einer guten oder schlechten Weise beeinflussen kann. Beginnen wir mit dem Einfügen des Codes unten in 3v4l. Behalten Sie die Konfiguration „alle unterstützten Versionen“ bei und klicken Sie auf „eval“.
namespace App;
strlen('ciao');
Nach der Ausführung des Codes wird ein Tab-Menü am unteren Bildschirm erscheinen. Navigieren Sie zum VLD Tab, um die entsprechenden Opcode可视化.
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
5 0 E > INIT_NS_FCALL_BY_NAME 'App%5CSpace%5Cstrlen'
1 SEND_VAL_EX 'ciao'
2 DO_FCALL 0
3 > RETURN 1
Beachten Sie, dass die erste Operation INIT_NS_FCALL_BY_NAME
ist. Der Interpreter baut den Namen der Funktion aus dem Namespace des aktuellen Dateisystems auf, aber er existiert nicht im App\Example
-Namespace — wie funktioniert das denn eigentlich?
Der Interpreter wird prüfen, ob die Funktion im aktuellen Namespace existiert. Wenn nicht, versucht er, die entsprechende Kernfunktion aufzurufen.
Hier haben wir die Gelegenheit, dem Interpreter zu sagen, dass er diese doppelte Überprüfung vermeidet und direkt die Kernfunktion ausführt.
Versuchen Sie, ein Backslash (\
) vor strlen
zu addieren und klicken Sie auf “eval”:
namespace App;
\strlen('ciao');
Im VLD-Tab können Sie nun die Opcode mit nur einer Anweisung sehen.
line #* E I O op fetch ext return operands
------------------------------------------------------------------------------------- 5 0 E > > RETURN 1
Weil Sie den genauen Ort der Funktion kommuniziert haben, muss er nicht an irgendeine Fallback-Option denken.
Wenn Sie das Backslash nicht verwenden möchten, können Sie die Funktion wie jede andere Klasse aus dem Wurzel-Namespace importieren:
namespace App;
use function strlen;
strlen('ciao');
Nutzen Sie automatische Opcode-Optimierungen
Es gibt auch viele interne Automatismen des PHP-Engines, um optimierte Opcode für die Beurteilung statischer Ausdrücke im Voraus zu generieren. Dies war einer der wichtigsten Gründe für die großartige Leistungsverbesserung von PHP seit Version 7.x.
Bei Kenntnis dieser Dynamik kann es Ihnen wirklich helfen, den Ressourcenverbrauch zu reduzieren und Kosten zu sparen. Nachdem ich diese Forschung durchführte, begann ich diese Tricks im gesamten Code zu verwenden.
Lassen Sie mich Ihnen ein Beispiel mit PHP-Konstanten zeigen. Führen Sie dieses Skript in 3v4l aus:
namespace App;
if (PHP_OS === 'Linux') {
echo "Linux";
}
Schauen Sie sich die ersten zwei Zeilen der PHP-Opcode an:
line #* E I O op fetch ext return operands
------------------------------------------------------------------------------------- 5 0 E > FETCH_CONSTANT ~0 'App%5CPHP_OS' 1 IS_IDENTICAL ~0, 'Linux' 2 > JMPZ ~1, ->4 6 3 > ECHO 'Linux' 7 4 > > RETURN 1
FETCH_CONSTANT
versucht, den Wert von PHP_OS
aus dem aktuellen Namespace zu erhalten, und sucht in dem globalen Namespace, da er hier nicht existiert. Dann führt die Anweisung IS_IDENTICAL
den IF
-Ausdruck aus.
Versuchen Sie nun, einen Backslash zu einer Konstante hinzuzufügen:
namespace App;
if (\PHP_OS === 'Linux') {
echo "Linux";
}
Wie Sie in der Opcode sehen können, muss der Engine nicht mehr versuchen, die Konstante abzurufen, weil sich nun klar ergibt, wo sie ist, und da es sich um einen statischen Wert handelt, hat er sie bereits im Speicher.
Außerdem ist der IF
-Ausdruck verschwunden, weil das andere Ende des IS_IDENTICAL
-Ausdrucks eine statische Zeichenkette ist (`’Linux’`), sodass der IF
als „true
“ markiert werden kann, ohne dass auf jeder Ausführung das Interpretieren überlastet werden muss.
Daher haben Sie viel Macht, um die Leistung Ihres PHP-Codes letztendlich zu beeinflussen.
Fazit
Ich hoffe, es war ein interessantes Thema. Wie ich am Anfang des Artikels erwähnte, profitiere ich erheblich von dieser Taktik und sie werden auch in unseren Paketen verwendet.
Sie können hier einen Beispiel sehen, wie ich diese Tipps in unserem PHP-Paket angewendet habe, um seine Leistung zu optimieren.
Wenn Sie mehr über die Herausforderungen lernen möchten, mit denen ein von Entwicklern getriebenes Unternehmen befasst ist, können Sie mich auf LinkedIn verfolgen.
Source:
https://dzone.com/articles/php-opcode-improve-application-performance