Die Performance des Objektmodells von PHP5 im Vergleich zu PHP4
Überraschung bei der Migration. Das neue Objektmodell von PHP5 bietet gegenüber dem von PHP4 eine ganze Reihe von Vorteilen. Endlich ist es möglich, einen Großteil der im Rahmen der objektorientierten Programmierung üblichen Verfahren einzusetzen. Das Resultat ist gut wartbarer, übersichtlich strukturierter und in der Regel auch schlankerer Code. Um so mehr überrascht es, wie sich nach der Migration eines Projekts von PHP4 nach PHP5 zeigte, dass die Performance zum Teil spürbar nachgelassen hat.
Der erste Verdächtige für diese Performance-Einbußen ist wohl das neue Objektmodell selbst. PHP ist im Kern keine objektorientierte Sprache, die Objekt-Features sind ähnlich wie bei Perl "sekundär". Das bedeutet auch, dass der Aufwand für den Interpreter der Komplexität des Objektmodells proportional ist. So fordert zum Beispiel die Prüfung, ob die Implementierung eines Interfaces korrekt ist, der Skript-Engine ganz offenbar einiges an Arbeit ab. Überraschend ist trotzdem, dass die Performance-Einbußen so deutlich sind im direkten Vergleich von PHP5 zu PHP4 - zumal Zend beansprucht, PHP5 sei sogar schneller als PHP4.
Rahmenbedingungen. Benchmarks sollten genaueren Aufschluss geben, welche Objekt-Features wie viel an Mehraufwand bedeuten. Zur Prüfung wurden die PHP-Versionen 4.3.10 und 5.0.3 in der CLI Variante mit der Option --enable-memory-limit compiliert. Die Tests liefen auf einer Maschine mit 1.1 GHz AMD Prozessor unter Linux 2.4.20 (Debian) mit 512MB RAM. Gemessen wurde die absolute Laufzeit, was gerechtfertigt erscheint, da das System während der Tests keinen zusätzlichen Belastungen unterlag. Keine der Testmethoden ruft I/O-Funktionen auf. Die Tests wurden unter verschiedenen Bedingungen in Schleifen von 100.000 bis 1.000.000 Durchläufen ausgeführt und die Ergebnisse dann gemittelt. Zudem wurde die Differenz des Speicherverbrauchs vor und nach Ausführung jeder Schleife gemessen; idealerweise sollte diese bei Null liegen.
Die Messungen beginnen in jedem Fall erst nach dem
kompletten Parserdurchlauf, so dass die Performance des Parsers nicht
Gegenstand des Benchmarks ist. Die Ausführung der
for
-Schleife selbst ist unter PHP5 übrigens sogar ein
wenig schneller als uner PHP4. Dies haben wir geprüft, um
auszuschließen, dass die Messergebnise von dieser Seite aus
beeinflusst werden.
Methoden. Da es für viele der neuen
Objekt-Features kein Äquivalent in PHP4 gibt, wurden die betreffenden
Eigenschaften für die 4er-Version in geeigneter Weise simuliert. So
wurde etwa als Gegenbeispiel für die Implementierung eines Interface
oder die Vererbung einer abstrakten Klasse die einfache Erweiterung
einer Klasse benutzt. Das Zerstören eines Objekts ruft in PHP4 keinen
Destruktor auf, in PHP5 den mit __destruct()
definierten. Die statische Variable von PHP5 wurde in PHP4 mit einer
globalen Variable, die Klassen-Konstante mit einer Objekt-Eigenschaft
nachgebildet.
Die Methoden werden nun im Einzelnen aufgeführt und kurz beschrieben:
bench_create
- ein Objekt wird erzeugtbench_destroy
- ein Objekt wird erzeugt und explizit zerstörtbench_create_get_string
- ein Objekt wird erzeugt und eine Methode aufgerufen, die einen String zrückgibtbench_create_get_array
- ein Objekt wird erzeugt und eine Methode aufgerufen, die einen Array zrückgibtbench_create_get_boolean
- ein Objekt wird erzeugt und eine Methode aufgerufen, die einen Boolean-Wert zrückgibtbench_create_get_static
- ein Objekt wird erzeugt und eine Methode aufgerufen, die eine statische Variable (Integer) zrückgibtbench_create_get_constant
- ein Obekt wird erzeugt und eine Klassenkonstante ausgelesenbench_create_clone
- ein Objekt wird kopiertbench_create_ref
- ein Objekt wird referenziert (PHP4$a =& $b
, PHP5$a = $b
)bench_pass_obj
- ein Objekt wird an eine Methode übergeben, die es zurückgibt (PHP4 als Referenz)bench_create_extends
- eine Klasse, die eine andere Klasse erweitert wird instanziiertbench_method_extends
- eine Klasse, die eine andere Klasse erweitert wird instanziiert und eine Methode der Instanz aufgerufenbench_create_abstract_impl
- eine Klasse, die eine abstrakte Klasse erweitert wird instanziiertbench_method_abstract_impl
- eine Klasse, die eine abstrakte Klasse erweitert wird instanziiert und eine Methode der Instanz aufgerufenbench_create_interface_impl
- eine Klasse, die ein Interface implementiert wird instanziiertbench_method_interface_impl
- eine Klasse, die ein Interface implementiert wird instanziiert und eine Methode der Instanz aufgerufen
Ergebnisse. Die gute Nachricht zuerst:
die neue Speicherverwaltung von PHP5 macht ihre Arbeit ganz offenbar
tatsächlich besser als die von PHP4. In der Regel ist der Gradient im
Speicherverbrauch geringer, nur in seltenen Fällen dem von PHP4
gleich. Einzig das Klonen eines Objekts mit clone
verbraucht mehr Speicher als das Äquivalent in PHP4 (die Gleichsetzung
zweier Objekte mittels des =
-Zeichens).

Auf der anderen Seite zeigt das Laufzeitverhalten von PHP5 verglichen mit dem von PHP4 ein sehr uneinheitliches Bild. Das Erzeugen und das Zerstören eines Objekts sind in der Tat schneller erledigt, ebenso das Erzeugen einer Objektreferenz. Alle anderen getesteten Features benötigen unter PHP5 jedoch mehr Zeit als unter PHP4.
Der zusätzliche Aufwand liegt bei unseren Tests zwischen 3 und 51
Prozent. Dabei schneiden die Implementierungen von Interfaces oder das
Vererben abstrakter Klassen besonders schlecht ab. Das Auslesen einer
Klassen-Konstanten erweist sich ebenfalls als teuer. Deutlich geringer
fallen die Leistungsunterschiede bei Features ins Gewicht, die auch
PHP4 schon unterstützt. Trotzdem sind sie auch dort
merklich. Möglicherweise kostet die Unterscheidung der Sichtbarkeit
nach private
, protected
und
public
nun doch einiges an Rechenzeit.
Diese Ergebnisse treffen so zumindest für die CLI Variante von PHP zu. Erste Versuche mit dem Apache-Modul zeigen jedoch, dass die Tendenz sich auch für diese Variante bestätigt.
Fazit. Das alles bedeutet jedoch
nicht, dass auf die Benutzung der neuen OOP-Festures verzichtet werden
sollte. Der Gewinn an Strukturiertheit, damit auch Zuverlässigkeit und
Wartbarkeit rechtfertigt geringe Leistungseinbußen durchaus. Abzuraten
ist jedoch zumindest für Webprojekte von der Verwendung von
Klassen-Konstanten sowie abstrakten Klassen/Methoden und
Interfaces. Eventuell können letztere bei der Entwicklung benutzt
werden, um die Einhaltung von Standards zu garantieren. Auf dem
Produktivsystem könnte die implements
-Klausel dann
auskommentiert werden, um dem Leistungseinbruch zu entgehen. Im
Einzelfall bleibt immer neu zu entscheiden, ob Zuverlässigkeit oder
Leistung im Vordergrund steht.
Nachtrag. Erste Tests mit PHP 5.1.0b3 zeigen, dass es Zend offenbar gelungen ist, die schlechte Performance von PHP5 in den Griff zu bekommen. Tatsächlich ist der Performancegewinn gegenüber PHP4 nun sehr deutlich. Wir werden an dieser Stelle einen ausführlichen Vergleich zwischen PHP 5.0.x und PHP 5.1.x nachreichen, sobald die endgültige Version ausgeliefert wird (siehe Benchmark 5.1.0).
2002 - 2008 © Ister.ORG