Wie man Geschwindigkeit aus PHP herausholt.

  • So, aus gegebenen Anlass, möchte ich euch das Thema Geschwindigkeit in PHP näher bringen.

    Das Ganze begann am Wochenende mit einer Diskussion zwischen meinem Bruder und mir mit dem Thema "Performance und Syntax von PHP". Es ist wohl klar, dass PHP in Sachen Geschwindigkeit nicht mit den Kontrahenten ASP.NET, JSP oder Python mithalten kann. PHP ist nun mal eine interpretierte Sprache und bietet damit nur eine relativ dürftige Performance.

    Das musste ich gestern in der Arbeit hart zu spüren bekommen. Ich entwickelte eine Suchfunktion für das aktuelle Projekt. Die Seite hat etwas mehr und größere Unterseiten und ich wollte keinen heuristischen Algorithmus entwickeln, sondern möglichst gute Ergebnisse geliefert bekommen. Außerdem sollte die Suche auf aktuelle Daten und nicht auf Indizes zugreifen.

    Das Ergebnis konnte sich sehen lassen: Tests ergaben die Ergebnisse, die wirklich perfekt passten. Doch das große Manko: Weil Tag-Clouds, Meta-Tags, Überschriften und Texte und Alternativtexte von Bildern einzeln gewichtet werden und deshalb einzeln geparst werden; weil passende Stücke aus durchaus großen Seiten herausgepickt werden (mit konfigurierbarer Länge); und weil Treffer visuell in den Abschnitten hervorgehoben werden - dauerte die Suche bei einer Stichwortsuche mit drei Begriffen in etwa drei Sekunden - Viel zu lange, für eine Suchfunktion einer Website!

    Deshalb habe ich mich etwas mit Geschwindigkeitsoptimierung von PHP-Scripten beschäftigt. Und siehe da: Ein paar kleine Änderungen hier und da: Qualitativ gleichbleibende Ergebnisse mit etwa einer Sekunde Laufzeit.

    Die wichtigsten 20 Punkte im Bereich PHP-Geschwindigkeitsoptimierung möchte ich euch im Folgenden präsentieren.

    Viele haben erst Auswirkungen, bei vielen Schleifendurchläufen oder langen Texten, doch alle haben einen Effekt - wie man an meinem Script sieht.

    ------------------------------------

    01. "Hallo ".$world; ist schneller als "Hello $world";. Das kommt daher, weil PHP beim parsen eines Strings

    viele Zeichen überprüfen muss. Durch das beenden des Strings vor dem Anketten einer Variable lässt PHP in einen dementsprechend schnelleren Modus umspringen.

    02. ' ist schneller als ". Dies hat einen ähnlichen Grund viel der vorherige Punkt. Bei " müssen einfach viel mehr steuerzeichen überprüft werden, als bei ', wo PHP mehr oder minder einfach drüberfährt.

    03. file_get_contents() und file_put_contents() ist schneller, als andere Methoden, um Dateien zu lesen. Die kommt ganz klar daher, dass PHP intern einfach keine Arrays oder ähnliches konstruieren muss.

    04. strpos() ist schneller als preg_match() - preg_match() ist schneller als ereg() - Auch die entsprechenden Replace-Funktionen. Das sollte auch jedem klar sein sein, warum. Deshalb immer vereinfachen versuchen.

    05. Bei zu speichernden Daten viel beim Eintragen rechnen. Auslesen kommt öfter vor. Wenn ihr etwa in Datenbanken, Dateien, o.Ä. eintragt, rechnet eher beim Eintragen. Wenn der Eintrag zehn mal ausgelesen wird, erspart ihr euch auch zehn Rechenzyklen.

    06. Wenn möglich, den Output zusammenfassen und auf einmal ausgeben. Die kommt daher, weil echo & Co. mit Datenverkehr verbunden wird. Das erklärt auch den häufigen header()-Fehler. Ein Template-System kann da viel helfen.

    07. PHP-Tags schließen, wenn ein langer Text ausgegeben wird. Bevor man mit echo einen langen Text, wie zum Beispiel den Grundaufbau der Seite ausgibt, sollte man eher mit ?> den PHP-Code beenden und auf "Inline-PHP" zugreifen.

    08. Output-Buffering und GZip-Kompression verwenden (falls möglich) ob_start() ist eine der nützlichsten funktionen in diesem Bereich. Hier wird jeglicher Output zwischengespeichert und kann anschließend, ähnlich einem Template-System verabreitet werden. Auch GZip-komprimierte Datenübertragungen können viel Geschwindigkeit bringen.

    09. OOP vermeiden. OOP ist eine grandiose Erfindung. Aber nicht für PHP. PHP ist und bleibt eine interpretierte Sprache. Und jede Klasse muss zuerst geparst werden. Außerdem dauert der Zugriff auf Elemente einer Klasse vier mal länger, als auch normale Variablen.

    10. Beim komplexen Algorithmen Schleifendurchgänge zusammenfassen. Falls ihr schon eine etwas komplexere Funktion mit vielen Schleifen geschrieben habt, werdet ihr die Gecshwindigkeit-Lecks von PHP sicher auch schon gesehen haben. Hier hilft es oft Schleifendurchgänge zusammenzufassen und Ausnahmekriterien (wie ersten und letztes Element) explizit zu behandeln. So fällt die überprüfung weg.

    11. Auch mal Heuristiken verwenden. Ein Algorithmus muss nicht immer perfekte Ergebnisse liefern. Gute reichen oft auch. Durch einen einfachen Denkanstoß, kann eine Heuristik große Geschwindigkeitsscüber bringen.

    12. Viel in den Speicher laden und auf Variablen zurückgreifen, nicht auf Funktionsaufrufe. Wenn ihr die Länge ienes String zehn mal bestimmen müsst, berechnet sie einmal und speichert sie in einer Variable. Zehn mal strlen() benötigt auch eine entsprechend höhere Laufzeit.

    13. Keine gleichbleibenden Berechnungen in Schleifen lassen, sondern vor die Schleife setzen. Niemals eine Schleife in der Form "for($i = 0; $i < count($array_a); $i++)" implementieren. Bei jedem Schleifendurchgang wird die mittlere Bedingung geprüft. Lieber vor der Schleife in eine Variable schreiben. Das gilt auch für Berechnungen innerhalb der Schleife, die in jedem Durchgang dasselbe Ergebnis liefern.

    14. Möglichst simple Variablen-Typen an Unterprogramme übergeben. Arrays und Objekte benötigen viel Rechenzeit. Deshab lieber die gewünschten Werte beim Aufruf auslesen und einzeln übergeben.

    15. Objekte und Arrays als Referenzen übergeben. Wenn es wirklich notwendig ist, Arrays und Objekte an Unterprogramme zu übergeben, tut dies per & und macht sie zu Referenzen. PHP kann darauf schneller zugreifen.

    16. Nicht mehr gebrauchte Arrays und Objekte per unset() löschen. Gerade diese großen Variablentypen benötigen viel Speicher. Wer sich schon mal mit dem Speicheraufbau eines Prozessors beschäftigt hat, wird mir zustimmen, dass das freigeben großer Bereiche Leben retten kann.

    17. Möglichst wenig Funtkionsaufrufe, wenn sie nicht unbedingt notwendig sind. Jeder Funktonsaufruf benötigt mehr Zeit, als eine normale Iteration. Deshalb lieber mal Code zwei oder drei mal kopieren, anstatt unnötige Unterprogrammaufrufe zu starten.

    18. Datenbanken sollten unbedingt indiziert werden. Das betrifft zwar nicht direkt PHP, aber viele Anwendungsbereiche PHPs. MySQL & Co. bekommen einen enormen GEschwindigkeitsschub durch einen Index.

    19. Zend bietet einen PHP Optimizer an, der das Laden und Interpretieren bis zu doppelt so schnell machen kann. Erklärt sich glaub ich von selbst ;D

    20. Webserveroptimierung: Das größte Optimierungspotential steckt jedoch im Server. Wie man diese genau konfigurieren sollte, könnt ihr hier nachlesen: http://phplens.com/lens/php-book/…bugging-php.php

    ------------------------------------

    Ich hoffe, ich konnte euch das Thema "Geschwindigkeit und PHP" etwas näher bringen. Ich wünsche euch viel Glück bei großen Projekten. Eure Benutzer werden euch kurze Rechenzeiten danken :)

    Bei meinem Script wurden vor Allem folgende Punkte implementiert: 01, 02, 03, 04, 06, 09, 10 (!), 12, 13, 14 15, 17.

    Liebe Grüße
    Dodo

    Something big is coming. And there will be pirates and ninjas and unicorns...

  • Zuerst zu deiner Liste womit man extremviel Zeit einsparrt:

    4. erreg Funktionen sollten nicht mehr verwendet werden..

    9. OOP wird nicht verwendet um Speed zu sparen, wer ohne OOP arbeitet wegen Speed der hat selber Schuld

    Auf die anderen WICHTIGEN Sachen gehe ich mal nicht ein :D

    Nun zu wichtigen womit man wirklich Zeit sparrt:

    1. Cache verwenden sprich DB abfragen, Datensätze cachen (Zend Cache oder ähnliches)
    2. Kompilierter Quelletext zwischenspeichern mit zb APC
    3. Queries meiden

  • Zuerst zu deiner Liste womit man extremviel Zeit einsparrt:


    JA, man siehts an meiner Suchfunktion ;D

    4. erreg Funktionen sollten nicht mehr verwendet werden..


    Hab ja auch niemandem gesagt, er soll sie verwenden, sondern eher hab eher abgeraten, oder? ;D

    9. OOP wird nicht verwendet um Speed zu sparen, wer ohne OOP arbeitet wegen Speed der hat selber Schuld


    Ja ich weiß, aber bei Scripts, die an sich schon viel LAufzeit benötigen, muss man diese nicht noch weiter raussteigern, oder?

    Auf die anderen WICHTIGEN Sachen gehe ich mal nicht ein :D


    Die wären? Ich habe nicht gesagt, dass alle viel bringen. Aber jeder bringt etwas. Und dies wird addiert. Vor allem die Schleifen fallen da rein.

    Nun zu wichtigen womit man wirklich Zeit sparrt:

    1. Cache verwenden sprich DB abfragen, Datensätze cachen (Zend Cache oder ähnliches)
    2. Kompilierter Quelletext zwischenspeichern mit zb APC
    3. Queries meiden

    Das was ich damit bezwecken wollte, ist die Script-Optimierung, weil gerade hier die größten Fehler gemacht werden. Warum, denkst du, bin ich denn auf die letzten beiden Punkte nicht näher eingegangen?

    Something big is coming. And there will be pirates and ninjas and unicorns...

  • Extra dafür registriert, weil das is ja zum Kringeln :D

    1. Stimmt nur je nach PHP-Version, zumal Konkatenation mit Strings in doppelten Anführungszeichen auch nich besonders schlau is (siehe 2).
    3. file_get_contents() ist nur eine Aneinanderreihung der Funktionen fopen(), fread(), und so weiter. Behauptung ohne Beleg, wundervoll...
    4. Das einfache Stringfunktionen schneller sind, als reguläre Ausdrücke ... Jaja, das liegt gaanz bestimmt an PHP ;) Die ereg_*()-Funktionen sind veraltet und sollten nicht mehr verwendet werden.
    5. Das ergibt irgendwie keinen Sinn :?
    6. Template-Engines sind mehr Overhead, als "der Datenverkehr". Bei echo schreibt PHP auch nur auf STDOUT, insofern: Kein Unterschied zu anderen Sprachen. PHP is selbst seine beste Template-Engine (siehe 7)
    8. Dir is schon bewusst, dass das Performance kostet und nicht bringt?
    9. Das is ma gaaanz großer Mist :D Was haben den Skript-Sprachen damit zu tun, ob Objektorierentierung schnell läuft, oder nicht? Das Interpretierende an Skript-Sprachen passiert direkt nach Einlesen der Datei. Danach verhält sich die Sprache, wie kompilierende Sprachen auch. Einfach Behauptungen ohne Beweise in Raum stellen, is wenig seriös. Und letzten Endes: Willste Performance, dann schreib in Assembler. OOP hatte in keiner Sprache jemals den Sinn gehabt riesige Performance-Schübe zu erzeugen. OOP ist ein Programmierparadigma, was vorallen strukturierte und wiederverwendbare Strukturen erzeugen soll. Das mit dem "4 mal langsamer" will ich übrigens mal sehen, das zweifle ich doch sehr stark an!
    10. Bei richtig geschriebenen Schleifen gibt es keine "Ausnahmefälle". "Geschwindigkeitslecks" hab ich auch nie festgestellt. Vielleicht mal mehr Speicher einbauen, oder regelmässig Variablen freigeben?
    11. Gilt für jede Sprache
    12. Gilt auch für jede Sprache und is so trivial, dass da jeder drauf kommen muss.
    13. Dir is schon klar, dass das das selbe ist, wie 12?
    14. Klar, da Kopien von Variablen (wie es bei Skalaren geschieht) bestimmt wesentlich effizienter sind, als Referenzen (wie bei Objekten/Arrays).
    15. Möp! Das is seit PHP5 Standard, unvermeidbar, steht im Manual, etc. Da wird ma nen Update fällig :D
    16. Immerhin: Bei PHP reicht nen unset(), gilt aber ansonsten (mehr oder weniger komplizierter) für alle Sprachen.
    17. Nennt sich "Iteration statt Rekursion" und gilt nicht nur für alle Programmiersprachen, sondern ist sogar schon in der Form in den Sprachentheorien bewiesen worden. Ist aber bei nährerer Betrachtung auch trivial: Bei jedem Funktionsaufruf wird der Call-Stack samt Scope gesichert, bei jeder Rückkehr wiederhergestellt.


    Zusammenfassend: Ich sag nicht, dass PHP der Performance-Booster schlechthin ist, aber man sollte nicht alles auf das Messer schieben, wenn der Koch damit nicht umgehen kann. Die Hälfte der genannten Punkte sind allgemeingültig und stellenweise sogar so trivial, dass ich mich schon Wunder, dass man sie noch extra erwähnen muss, vorallen wenn man damit versucht einer einzelnen Sprache etwas in die Schuhe zu schieben. Dann wiederum ist eine Hälfte der "Argumene" schlicht geraten. Dann werden "Konzepte" und "Performance" in ein Mixer gepackt und kräftig gerührt.

    Ruhig das nächste mal mehr Mühe bei der Auswahl der "Argumente" geben, wenn man eine einzelne Sprache aus reiner Unmut dissen will ;)

    Zitat

    Hab ja auch niemandem gesagt, er soll sie verwenden, sondern eher hab eher abgeraten, oder? ;D

    Sie sind schlicht veraltet. Da is die Laufzeit wurscht. Wird nebenbei eh nicht mehr gewartet, soweit ich weiß.

    Zitat

    Ja ich weiß, aber bei Scripts, die an sich schon viel LAufzeit benötigen, muss man diese nicht noch weiter raussteigern, oder?

    "viel Laufzeit"? Zahlen! ;)

    Zitat

    Das was ich damit bezwecken wollte, ist die Script-Optimierung, weil gerade hier die größten Fehler gemacht werden. Warum, denkst du, bin ich denn auf die letzten beiden Punkte nicht näher eingegangen?

    Das heißt also "Sprache langsam", aber wie es wirklich schneller geht (und man trotzdem sauber programmiert) wird verheimtlicht?

    Einmal editiert, zuletzt von KingCrunch (21. Juli 2010 um 21:15)

  • Lieber KingCrunch:

    Ich habe am Ende meiner Beitrags meine Hauptquelle gepostet. Ich behaupte nicht, wenn ich nicht vorher von mehreren diese Aussage bestätigt bekommen habe.

    Ja, auch viele Punkte sind allgemein. Das ist nunmal so, wenn man eine CODE-Optimierung anwendet. Code gibts in jeder Sprache und sieht in den meisten Hochsprachen gleich aus.

    Und zu den trivialen Punkte. Ja. Sie sollten klar sein, aber sie passieren trotzde,. Und wenn nur EINER keinen count()-Befehl mehr in den Schleifenkopf postet, hat sich sich mein Beitrag bereits ausgezahlt.

    Zu OOP: Eine interpretierte Sprache verhält sich keinesfalls wie eine ausgeführte Sprache. Zuerst muss auf syntaktische Korrektheit geprüft werden - Das fällt durch das Compilieren weg bei ausgeführten Sprachen weg. Bei Compilierte Sprachen werden Klassen im vornherein in eigene Speicherstrukturen umgewandelt. Das kann bei PHP nicht der Fall sein, weil diese Struktur bei jedem Script-Aufruf berechnet und erstellt werden muss. Beim Zugriff auf Objekte muss in PHP jeder Teil einzeln aufgelöst werden. Dass da viel berücksichtigt wird, zeigt, dass $this->$variable klappt. Da wird sogar die Position der Speicherzelle errechnet.
    Dieses ganze Rechnen fällt bei compilierten Sprachen weg, weil alles auf statische Speicheradressen umgerechnet wird.
    Bei normalen Variablenzugriffen unter PHP fallen all die Punke auch weg, weil keine Objekte berücksichtigt werden. Und da sollte jedem Menschen mit etwas programmiertechnischen Hausverstand klar sein, dass OOP in PHP - relativ gesehen - enorme Geschwindigkeitseinbußen bringt.

    War das eines der "Argumente", das du gemeint hast? Wie wäre es, wenn du dich selbst mal mit ein paar anderen Sprachen auseinandersetzt, damit du vergleichen kannst...

    Und ich will PHP keinesfalls "dissen", wie du gemeint hast. Ich programmiere nun jahrelang PHP und bevorzuge diese Sprache, wegen der Dynamik des Syntax. Aber ist nunmal Fakt, dass PHP im Bereich der Geschwindigkeit neben seinen großen Kollegen, wie JSP oder ASP.NET untergeht.
    Deswegen wollte ich den Code schreiben. Denn gerade die Dynamik des PHP-Codes ist das, was Programmierer dazu verleitet, ineffizienten Code zu schreiben.

    Edit: Zu dem mit dem Dateien lesen:
    Ich hab gerade ein Testscript geschrieben. Drei absolut gleiche Archive - nur der Name unterscheidet sich.
    Jedes Archiv wird mit folgendem Code zehn mal eingelesen:

    Folgende Ausgabe kam zustande:

    Code
    file_get_contents(): 0.86298608779907
    file(): 1.2042920589447
    fgets(): 2.545175075531


    So... Ich warte auf deine Antwort, toller PHP-Kenner... -.-

    Edit2: Zu dem mit dem schneller gehen: Hab ich doch gesagt. Ich ich erinnere mich niemandem gesagt zu haben, er/sie solle unsauber programmieren.

    Something big is coming. And there will be pirates and ninjas and unicorns...

    2 Mal editiert, zuletzt von Dodo (21. Juli 2010 um 22:02)

  • Ich muss mich da leider auchnoch einmischen:

    Zitat von KingCrunch


    3. file_get_contents() ist nur eine Aneinanderreihung der Funktionen fopen(), fread(), und so weiter. Behauptung ohne Beleg, wundervoll...


    Also ich ahbe da ein script(eigenes CMS) auf nem Server, dass Dateien grundsätzlich mit fopen(); liest. Jetzt hat das alles auch auf XAMPP & bplaced geklappt, aber ich wollte es auf einem schnelleren erver testen und dann bekam ich die Meldung, ich hätte nicht die Rechte dazu. Also hab ich die fopen(); konstrukte durch file_get_contents(); erstzt und die datei wurde eingelsen - Fällt dir was auf?
    Und nein, 12. ist != 13! Es ist was anderes, wenn du 12. in einer schleife anwendest oder dich nach 13. richtest.

    P.S.:
    Ich hatte mal wissen wollen, wieviel MB ich einspare, wenn ich bei c.a 70k PMS/Tag pro PM 63 Zeichen spare. Habe also 70K mal
    - 2x range("A", "Z")
    - range("A", "k")
    - das ganze durch strshuffle
    ausgeführt und in eine Datei geschreiben (4,07MB) - Das hat weniger als ne halbe sekunde gedauert.

    Der, der weiß dass er nichts weiß, weiß mehr als der, der nicht weiß, dass er nichts weiß.

    Wer nach etwas fragt, geht grundsätzlich das Risiko ein, es auch zu bekommen!

  • @Dodo vergiss es KingCrunsh ist ein PHP Kenner ;)

    Weis ja net wieviel Millionen Schleifendurchgänge benötigt hast

    Wenn diese Optimierungen bei dir einen enormen Schub gebracht haben dann muss ich echt sagen das du was falsch gemacht hast


    mfg

  • @Dodo vergiss es KingCrunsh ist ein PHP Kenner ;)

    Also wenn ich mir den Stuss über OOP uns file_get_contents() durchlese, dann kann ich über diese Behauptung wirklich nur lachen.

    Wenn diese Optimierungen bei dir einen enormen Schub gebracht haben dann muss ich echt sagen das du was falsch gemacht hast

    Ja ich weiß, dass ich was falsch gemacht habe. Ich habe ja auch dazugeschrieben, wrlche Punkte ich alle berücksichtigt habe. Mir vielen heute noch ein paar Schleifendurchgänge auf, die man sparen kann. Jetzt benötigt die Suchfunktion nur noch etwa eine halbe Sekunde.
    Ich WEI?, dass ich das Script vorher schlecht programmiert habe und deswegen hab ich ja auch nach Optimierungen gesucht. Und diese Optimierungen habe ich gefunden. Und sie haben einen enormen Schub gebracht. Deshalb wollte ich das hier posten.

    Denn, wenn jemand mal dasselbe Problem hat, dann kann er hier vielleicht Lösungsansätze finden.

    Something big is coming. And there will be pirates and ninjas and unicorns...

  • Das stimmt...

    Meine Meinung zu OOP ist das OOP absolute PFLICHT ist, wenn man an der Zeit was schrauben muss dann bitte nicht über OOP es gibt ja genug Methoden....Dann kann ich nähmlich wie KingKrunsh es spaßeshalber sagte auch Assambler/C++ nehmen

    ZUdem Script:
    Legt file get contents in den Ram.
    Vergleichst du Tomaten mit Äpfel, den fgets Zeilenweise einliest wäre dumm wenn das schneller gehen würde

    mfg

  • ZUdem Script:
    Legt file get contents in den Ram.
    Vergleichst du Tomaten mit Äpfel, den fgets Zeilenweise einliest wäre dumm wenn das schneller gehen würde

    Nein ich vergleiche nicht Tomaten mit Äpfeln. Ich habe vorhin gesagt, dass file_get_content() schneller zu Dateien lesen ist, als die anderen. Die anderen lesen auch Dateien und sind auch dafür da.

    Something big is coming. And there will be pirates and ninjas and unicorns...

  • Ich muss sagen: Dynamische Typisierung und das ganze String-basierte Zeug ist scheiße, unnötig (was man mit dem String-Kram an Flexibilität gewinnt, sollte man lieber zur Compile-Zeit mit Meta-Programmierung machen und so viel wie möglich über Pointer und Integers gehen, ich beziehe mich z.B. auf callbacks in PHP und ^^get und solche Späße). Die Erfinder von diesen Script-Sprachen hätten lieber mal gescheite Typ-Inferenz implementieren sollen. file_get_contents ist manchmal sinnvoll und manchmal nicht. Wenn man sowieso den Text dann parsen will oder so etwas, ist ein zeichen-/zeilenweises Einlesen u.U. schneller, kann natürlich sein, dass die Calls da Zeit verschwenden, Speicher spart man aber sicher.

    Ein Tipp von mir:
    Berechnungen auf Arrays nicht durch Verkettung vieler Standard-Array-Funktionon implementieren, lieber mal selber ein paar Schleifen schreiben, die die Sache schnell und direkt erledigen, in Haskell kann man sich dank lazyness und Optimizer so Sachen oft noch erlauben, in PHP nicht.
    Regexps sollten auch nicht für jede String-Operation benutzt werden, lieber in einer Schleife durchgehen, nen kleinen Parser schreiben, whatever, manchmal sieht man auch oft wiederholt angewandte regexp-hacks, das ist lahm.
    Kein eval benutzen…
    Warnungen nicht ignorieren. Ich dachte erst, viele E_NOTICE-Sachen wären egal, z.B. der Zugriff auf ein nicht vorhandenes Element im Array, doch eine kurze isset-Überprüfung belastet i.d.R. PHP weniger, als wenn ein Fehler ausgelöst wird, der dann erst wieder per @ unterdrückt werden muss, das dauert lange. Wenn das natürlich die Ausnahme ist, gilt das nicht, aber wenn man sowieso überprüfen muss, dann eher mit isset, z.B. bei „if($x = @$y['x'])“, „$y[x]“ ist auch ganz schlecht.

    Für 17 benutze ich gerne so C-style-Makros.

    Nr. 11 ist einfach nur Schwachsinn.
    ob_start würde ich auch empfehlen, aber macht es die Sache schneller?
    1 stimmt im Prinzip, finde das auch eleganter, aber sobald es einmal geparst ist macht das nichts mehr. Kein Laufzeiteffekt…
    14 ist sinnlos, die kleine Objektreferenz tut doch nicht weh, da können die Sachen bei Bedarf rausgeholt werden. So blähst du die Patameteranzaht auf, der Aufruf wird komplizierter und nicht schneller.
    15 Bin mir nicht sicher, ob der das nicht ganz gut selber optimiert bekommt. Aber kann nicht schaden.


  • 01. "Hallo ".$world; ist schneller als "Hello $world";. Das kommt daher, weil PHP beim parsen eines Strings viele Zeichen überprüfen muss. Durch das beenden des Strings vor dem Anketten einer Variable lässt PHP in einen dementsprechend schnelleren Modus umspringen.


    Ändert sich gelegentlich mit den PHP-Versionen. Unter 5.3.0 und aktueller Version 5.3.3 folgender Benchmark:

    Ergebnis:
    "Hallo {$var} - "
    0.51526999473572
    "Hallo $var - "
    0.51192283630371
    "Hallo ".$var." - "
    1.0051839351654
    'Hallo '.$var.' - '
    1.0279681682587

    Hat mich auch ziemlich erstaunt. Persönlich bevorzuge ich allerdings die Schreibweise "Hallo ".$var." - "
    Zum einen da durch das Konkatenieren eine bessere Lesbarkeit gegeben ist. Zum anderen brauchen bei SQL-Statements die einfachen Hochkommata ' nicht escaped zu werden.


    02. ' ist schneller als ". Dies hat einen ähnlichen Grund viel der vorherige Punkt. Bei " müssen einfach viel mehr steuerzeichen überprüft werden, als bei ', wo PHP mehr oder minder einfach drüberfährt.


    Naja, nach der Logik dürfte es aber keinen Unterschied zwischen Konkatenierung und direkter Einbindung geben, bei doppelten Hochkommata ". Entweder muss der String nach Variablen geparst werden, oder nicht.


    03. file_get_contents() und file_put_contents() ist schneller, als andere Methoden, um Dateien zu lesen. Die kommt ganz klar daher, dass PHP intern einfach keine Arrays oder ähnliches konstruieren muss.


    Das glaube ich dir einfach mal, habe selber keine Benchmarks dazu gemacht. Klingt aber einleuchtend. Allerdings ist es natürlich gelegentlich auch nötig eine Datei zeilenweise als Array einzulesen. Kommt bei mir häufiger vor.
    Wenn man nur die Funktionalität von file_get_contents() benötigt hast du wie gesagt sicherlich recht.

    04. strpos() ist schneller als preg_match() - preg_match() ist schneller als ereg() - Auch die entsprechenden Replace-Funktionen. Das sollte auch jedem klar sein sein, warum. Deshalb immer vereinfachen versuchen.


    Signed.
    Mal davon abgesehen, das ereg() sowieso bald bei PHP rausfliegt und nicht mehr verwendet werden sollte.

    05. Bei zu speichernden Daten viel beim Eintragen rechnen. Auslesen kommt öfter vor. Wenn ihr etwa in Datenbanken, Dateien, o.Ä. eintragt, rechnet eher beim Eintragen. Wenn der Eintrag zehn mal ausgelesen wird, erspart ihr euch auch zehn Rechenzyklen.


    Signed.
    Eine Selbstverständlichkeit in meinen Augen. Es werden nur die Daten gespeichert die benötigt werden, und nicht alle möglichen anderen Daten die zusammen erst die Daten ergeben die ich benötige.

    06. Wenn möglich, den Output zusammenfassen und auf einmal ausgeben. Die kommt daher, weil echo & Co. mit Datenverkehr verbunden wird. Das erklärt auch den häufigen header()-Fehler. Ein Template-System kann da viel helfen.


    Signed.
    Und "wenn möglich" heißt hier nahezu "immer" (mir fällt grad kein Beispiel ein wo es nicht möglich wäre).
    Ich persönlich nutze jetzt seit einem Weilchen Smarty, sowas hier scheint mir aber auch gar nicht mal so verkehrt:
    http://mylittlehomepage.net/de/sonstiges/u…emplate-engines

    07. PHP-Tags schließen, wenn ein langer Text ausgegeben wird. Bevor man mit echo einen langen Text, wie zum Beispiel den Grundaufbau der Seite ausgibt, sollte man eher mit ?> den PHP-Code beenden und auf "Inline-PHP" zugreifen.


    Sowieso, da ich eh für eine strikte Trennung von Code und Ausgabe bin.

    08. Output-Buffering und GZip-Kompression verwenden (falls möglich) ob_start() ist eine der nützlichsten funktionen in diesem Bereich. Hier wird jeglicher Output zwischengespeichert und kann anschließend, ähnlich einem Template-System verabreitet werden. Auch GZip-komprimierte Datenübertragungen können viel Geschwindigkeit bringen.


    Mag stimmen, OB sollte aber überflüssig sein, wenn man Code und Ausgabe sauber nach dem EVA-Prinzip trennt.

    09. OOP vermeiden. OOP ist eine grandiose Erfindung. Aber nicht für PHP. PHP ist und bleibt eine interpretierte Sprache. Und jede Klasse muss zuerst geparst werden. Außerdem dauert der Zugriff auf Elemente einer Klasse vier mal länger, als auch normale Variablen..


    Naja...
    Natürlich hast du rein auf die Geschwindigkeit bezogen recht. Aber so ein Rat passt hier trotzdem nicht im geringsten rein, weil es bei OOP um ganz andere Dinge geht, als um die Geschwindigkeit. Ich weiß ja nicht was du für PHP-Projekte realisierst, aber wenn du in einem Team ein voll dynamisches, modular erweiterbares, wiederverwendbares System entwickelst, möchte ich mal sehen wie du das mit prozeduralem Code managest. ;)
    Mal ganz abgesehen von der jederzeitigen Wiederverwendbarkeit gut geschriebener Klassen, deren Abstraktionsebene eine anpassungsfreie Einbindung in nahezu jedes Projekt ermöglicht.
    Kurz, die Frage ob OOP oder prozedurale Programmierung wird durch die Komplexität des Pojektes bestimmt, nicht nach Geschwindigkeitsvorteilen.
    Mal abgesehen davon, dass das Klassenmodell in PHP5 wirklich schon gut ist.
    http://professionelle-softwareentwicklung-mit-php5.de/

    10. Beim komplexen Algorithmen Schleifendurchgänge zusammenfassen. Falls ihr schon eine etwas komplexere Funktion mit vielen Schleifen geschrieben habt, werdet ihr die Gecshwindigkeit-Lecks von PHP sicher auch schon gesehen haben. Hier hilft es oft Schleifendurchgänge zusammenzufassen und Ausnahmekriterien (wie ersten und letztes Element) explizit zu behandeln. So fällt die überprüfung weg.


    Schleifendurchgänge weitestgehend möglich zusammenfassen ist klar, Selbstverständlichkeit. Aber irgendwie verstehe ich gar nicht was du meint wie man es nicht machen sollte :D

    11. Auch mal Heuristiken verwenden. Ein Algorithmus muss nicht immer perfekte Ergebnisse liefern. Gute reichen oft auch. Durch einen einfachen Denkanstoß, kann eine Heuristik große Geschwindigkeitsscüber bringen.


    Das mag wohl sein. :)

    12. Viel in den Speicher laden und auf Variablen zurückgreifen, nicht auf Funktionsaufrufe. Wenn ihr die Länge ienes String zehn mal bestimmen müsst, berechnet sie einmal und speichert sie in einer Variable. Zehn mal strlen() benötigt auch eine entsprechend höhere Laufzeit.


    Richtig, es ist sogar fast 3x so schnell:

    Ergebnis:
    0.46727013587952
    0.16079497337341

    13. Keine gleichbleibenden Berechnungen in Schleifen lassen, sondern vor die Schleife setzen. Niemals eine Schleife in der Form "for($i = 0; $i < count($array_a); $i++)" implementieren. Bei jedem Schleifendurchgang wird die mittlere Bedingung geprüft. Lieber vor der Schleife in eine Variable schreiben. Das gilt auch für Berechnungen innerhalb der Schleife, die in jedem Durchgang dasselbe Ergebnis liefern.


    Ich verstehe zwar den Unterschied zu 12. nicht, aber es stimmt immer noch.

    14. Möglichst simple Variablen-Typen an Unterprogramme übergeben. Arrays und Objekte benötigen viel Rechenzeit. Deshab lieber die gewünschten Werte beim Aufruf auslesen und einzeln übergeben.

    Ergebnis:
    sum_a($array)
    1.5093479156494
    sum_b()
    1.4196450710297
    Der Unterschied ist nicht wirklich signifikant.

    15. Objekte und Arrays als Referenzen übergeben. Wenn es wirklich notwendig ist, Arrays und Objekte an Unterprogramme zu übergeben, tut dies per & und macht sie zu Referenzen. PHP kann darauf schneller zugreifen.


    Für Arrays hast du recht. Objekte werden aber sowieso als Referenz übergeben. Wenn man Objekte kopieren will braucht man "clone".

    16. Nicht mehr gebrauchte Arrays und Objekte per unset() löschen. Gerade diese großen Variablentypen benötigen viel Speicher. Wer sich schon mal mit dem Speicheraufbau eines Prozessors beschäftigt hat, wird mir zustimmen, dass das freigeben großer Bereiche Leben retten kann.


    Ich habe mich noch nicht mit dem Speicheraufbau eines Prozessors beschäftigt, klingt aber einleuchtend.

    17. Möglichst wenig Funtkionsaufrufe, wenn sie nicht unbedingt notwendig sind. Jeder Funktonsaufruf benötigt mehr Zeit, als eine normale Iteration. Deshalb lieber mal Code zwei oder drei mal kopieren, anstatt unnötige Unterprogrammaufrufe zu starten.


    Also wenn ich sowas lese... Natürlich hast du in Bezug auf die Geschwindigkeit recht. Aber was sämtliche andere Belange der Programmierung angeht, als gravierendste Punkte Abstraktion/Wiederverwendbarkeit und Wartbarkeit, ist dieser Tipp noch größerer Unsinn als das Abraten von OOP bei PHP.

    18. Datenbanken sollten unbedingt indiziert werden. Das betrifft zwar nicht direkt PHP, aber viele Anwendungsbereiche PHPs. MySQL & Co. bekommen einen enormen GEschwindigkeitsschub durch einen Index.


    Mal abgesehen vom obligatorischen Primärschlüssel ist diese Aussage keinesfalls allgemeingültig. Das Auslesen geht schneller über Indices. Das Schreiben in/Aktualisieren eine/r Tabelle mit Indices dauert aber länger. Daher sollten Tabellen aus denen mehr gelesen wird mit nötigen Indices versehen werden, Tabellen in die mehr geschrieben/in denen mehr aktualisiert wird sollten möglichst frei von Indices gehalten werden.
    Gegebenenfalls kann es Sinn machen eine Tabelle in die normalerweise nur geschrieben wird vor dem Auslesen vieler Datensätze mit einem Index zu versehen und diesen danach wieder zu entfernen, bzw. bei einer Tabelle aus der meist nur gelesen wird Indices zu entfernen wenn viele Datensätze reingeschrieben/aktualisiert werden, und die Indices danach wieder zu setzen.

    19. Zend bietet einen PHP Optimizer an, der das Laden und Interpretieren bis zu doppelt so schnell machen kann. Erklärt sich glaub ich von selbst ;D


    Naja, ich tendiere da ja doch eher zu APC.
    http://blog.digitalstruct.com/2007/12/23/php…zend-framework/

    20. Webserveroptimierung: Das größte Optimierungspotential steckt jedoch im Server.


    Obligatorisch.

    "Programming today is a race between software engineers
    striving to build bigger and better idiot-proof programs,
    and the universe trying to build bigger and better idiots.
    So far, the universe is winning."
    Rick Cook

  • Mal ein paar kleine Ergänzungen noch, die unabhängig vom Softwaredesign des PHP-Codes sind:

    Mysql - Datums-/Zeitspeicherung
    Zur Speicherung von Datums- oder Zeitwerten die vorgesehenen Feldtypen nehmen (Date, Datetime, Timestamp, Time, Year). Also keine INT-Felder mit unix-timestamps füllen, oder noch schlimmer Varchar-Felder verwenden.
    Mit den vorgesehenen Feldern kann Mysql hervorragend rechnen, Formatierungen und Umformungen vornehmen. Das ist um einiges schneller als die erforderlichen Berechnungen und/oder Umformungen nach dem Auslesen mit PHP vorzunehmen.
    Ich empfehle da jedem sich mit den Datums- und Zeitfunktionen von Mysql vertraut zu machen.

    switch-case-/if-elseif-if-Optimierung
    Sowohl bei switch-Anweisungen, als auch bei if-elseif-if-Konstrukten sollten die Bedingungen die am häufigsten eintreten oben stehen. Sobald dieser Falls auftritt verlässt PHP die Anweisung und spart sich die restlichen Überprüfungen.

    if-Bedingungen: Reihenfolge optimieren
    Ähnliches gilt für mehrere Bedingungen in einer if-/elseif-Abfrage. Bei &&-Verknüpfungen sollten hier die Prüfungen die am häufigsten Fehlschlagen ganz vorne stehen, da PHP in diesem Fall die restlichen Überprüfungen nicht mehr durchführt (-> Kurzschlussauswertung).
    Für ||-Verknüpfungen gilt das Gegenteil: Die Bedingungen die am häufigsten erfüllt werden sollten vorne stehen.


    Einige Selbstverständlichkeiten, die aber leider trotzdem häufig "falsch" gemacht werden:

    Mysql - LIMIT verwenden
    In SELECT-Abfragen sollte LIMIT verwendet werden, sofern nur eine bestimmte Anzahl Ergebniszeilen benötigt wird.

    Filterfunktionen der Datenbank nutzen
    SELECT-Abfragen sollten so formuliert sein, dass sie nur genau die Daten liefern die man auch benötigt. In PHP sollte optimalerweise keinerlei Filterung mehr nötig sein.

    Kein SELECT * verwenden
    http://www.php-faq.de/q-sql-select.html

    COUNT() statt mysql_num_rows
    Wenn man nur die Anzahl der Ergebniszeilen ohne die Ergebnisse selber benötigt, sollte die SQL-Funktion COUNT() verwendet werden, statt sich den Speicher mit dem kompletten Ergebnis zuzumüllen bei dem man dann nur via PHP die Anzahl der Zeilen ausliest.

    "Programming today is a race between software engineers
    striving to build bigger and better idiot-proof programs,
    and the universe trying to build bigger and better idiots.
    So far, the universe is winning."
    Rick Cook