Blog

Simon Simon
25.07.2016 20:39

PHP Performanceoptimierung von lenex-php


Im Rahmen des Projekts "Lxf2Html" für woum.at erfolgte eine Performanceoptimierung der Bibliothek lenex-php.

Der lxf2html Konverter konvertiert lxf Dateien in html. Die lxf Dateien sind elektronische Ergebnisdateien im europäischen Schwimmsport. Mit dem Konverter ist es möglich, die gesamten Ergebnisse eines Schwimmwettkampfes nach Clubs und Schwimmer bzw Schwimmerin durchzuklicken. Zwischenzeiten und Einzelzeiten der Schwimmer bei Staffeln werden ebenfalls berechnet und dargestellt. Die jeweils erreichten Punkte können für verschiedene Punktesysteme ausgegeben werden : FINA Punkte, Rudolph Punkte, Italienische Masters Punkte und DSV Masters Punkte. Die Ergebnisse können in unterschiedlichen Sprachen (Deutsch, Englisch, Italienisch, Französisch, ..) dargestellt werden. Weitere Details zum Lenex Konverter.

Eine Performanceanalyse mittels XDebug und Darstellung mittels webgrind ergab folgende Ergebnisse:

Das Einlesen und Parsen einer unkomprimierten Lenex-Ergebnisdatei mit 900kb mit der Originalversion der Bibliothek dauerte ca. 7,3 Sekunden (die Ausführungszeiten sind aufgrund des XDebug-Profilers erhöht). Mittels der Performanceanalyse konnte der Flaschenhals schnell ausfindig gemacht werden: Für den Zugriff auf die Properties der Model-Klassen wurde die PropertyAccess Komponente des Symfonfy Frameworks verwendet. Da bei den entsprechenden get und set Methoden keine Typenüberprüfungen oder sonstige Überprüfungen erfolgten, sind diese nicht unbedingt notwendig. Das Umschreiben des Zugriffs auf die Properties der Model-Klassen erbrachte folgendes Ergebnis: das Einlesen und Parsen einer unkomprimierten Lenex-Ergebnisdatei mit 900kb ohne Symfony PropertyAcces  benötigte nur noch zwischen 1,14 und 1,36 Sekunden. Dazu musste die Sichtbarkeit der Objekteigenschaften von protected auf public geändert werden.

Ein Performancetest ergab, dass der "dynamische" Zugriff auf Objekteigenschaften praktisch gleich schnell ist, wie der direkte Zugriff:

Count: Testing of setting 3 times 300000 = 900000 property values
Setting properties using direct accessing took 2.2677540779114s
Setting properties using dynamic accessing took 2.2825977802277s
Setting properties using array simulation took 9.5236191749573s
Setting properties using mapper took 5.1776850223541s
 

Der Performancetest verwendet verschiedene Mapping-Implementierungen (die etwas unkonventionell sind):

  • direct accessing: Jede Eigenschaft wird direkt zugewiesen
  • dynamic accessing: der Eigenschaftsname, in den geschrieben wird, steht in einer Variablen
  • array simulation: das Objekt enthält keine wirklichen Eigenschaften, sondern lediglich eine Eigenschaft. Diese ist vom Typ Array und enthält alle Eigenschaften. Der Zugriff wird mittels der magischen Methode "__get" auf den Array umgeleitet
  • mapper: die Eigenschaften stehen in einem Array und werden an eine Mapping Methode der Klasse übergeben, die die Eigenschaftten mittels der direkten Zuweisen überträgt.

Die Parsing-Funktionen wurden komplett neu mittels Reflection geschrieben, da die dynamische Zuweisung kaum Performanceinbußen bring, aber viel Code einspart. Danach benötigte die Datei nurmehr 0,41 Sekunden für den Einlese- und Parsevorgang. Denn ein weiterer Flaschenhals der Implementierung ist der rekursive Aufruf von Funktionen. Ohnehin benötigt ein Funktionsaufruf in PHP relativ viel Zeit.

Original-Webgrind-Screenshot, Neuentwicklung-Webgrind-Screenshot

Die Struktur der Originalimplenetierung definierte zum Parsen eines Objekts einen Array, der die Mappings enthielt. Zudem werden Objekteigenschaften, die in einem Kind-XML-Element definiert werden in einer dynamischen Funktion (Closure) eingelesen. Einerseits werden diese Mapping-Arrays nicht gecached und andererseits verursacht das Definieren der Closures in dem Array unnötige Verschachtelungen.


: php performance, symfonfy PropertyAccess, property access, reflection
: 27. Juli 2016 17:13
Link zu diesem Artikel: (in die Zwischenablage)