T-Rex: Datei include dauert sehr lange

Moin,

wir durch sieben aktuell unseren Code mit Profiling maßnahmen. Wir wollen gucken wie schnell oder langsam bestimmte komponente der Seite sind. Da sind wir auf einen Dateiinklude gestossen.
Es wird eine Datei inkludiert die ist 61 KB (1700 Zeilen) groß und braucht ca. 0.26 Sekunden bis sie eingebunden ist. Zum Vergleich, die Datei die auf dieser Seite als zweit langsamstes geladen wird, braucht ist 18 KB (500 Zeilen) groß und braucht ca. 0.001 Sekunden zum laden.

Welche Ursachen kann ein derartig langsames laden haben und wie kann ich es beschleunigen?

Gruß
von PHP enttäuschter
T-Rex

  1. Moin!

    wir durch sieben aktuell unseren Code mit Profiling maßnahmen. Wir wollen gucken wie schnell oder langsam bestimmte komponente der Seite sind. Da sind wir auf einen Dateiinklude gestossen.
    Es wird eine Datei inkludiert die ist 61 KB (1700 Zeilen) groß und braucht ca. 0.26 Sekunden bis sie eingebunden ist. Zum Vergleich, die Datei die auf dieser Seite als zweit langsamstes geladen wird, braucht ist 18 KB (500 Zeilen) groß und braucht ca. 0.001 Sekunden zum laden.

    Welche Ursachen kann ein derartig langsames laden haben und wie kann ich es beschleunigen?

    Include bindet Code nicht nur einfach extern ein, sondern führt ihn auch aus, wenn er nicht innerhalb von Klassen- oder Funktionsdeklarationen steht.

    Die Größe der Datei ist recht irrelevant, entscheidend ist das, was dadurch passiert.

    Gruß
    von PHP enttäuschter
    T-Rex

    Ihr setzt doch hoffentlich schon einen Opcode-Cache wie APC ein? Das ist die einfachste Performanceoptimierung, die man kostenlos haben kann.

    - Sven Rautenberg

    1. Include bindet Code nicht nur einfach extern ein, sondern führt ihn auch aus, wenn er nicht innerhalb von Klassen- oder Funktionsdeklarationen steht.

      da sind ja nur Klassen drin. Es sind auch keinerlei weiteren includes vorhanden oder versteckte aufrufe.

      Ihr setzt doch hoffentlich schon einen Opcode-Cache wie APC ein? Das ist die einfachste Performanceoptimierung, die man kostenlos haben kann.

      Gut das ist mir neu :D. Mal gucken was dass nun wieder ist... hab eigentlich gedacht 61 kb wäre eine zu vernachlässigen größe.

      Gruß
      APC ABC 321
      T-Rex

  2. hi,

    Welche Ursachen kann ein derartig langsames laden haben und wie kann ich es beschleunigen?

    Der Code in der Datei wird kompiliert, das macht dem Parser zu schaffen ;)

    In Perl würde ich den Autoloader empfehlen, damit ist es möglich, Code auszulagern, der erst auf Anforderung kompiliert wird. Beispielsweise Klassen oder Methoden/Funktionen, die nicht so oft gebraucht werden.

    Mit Perl/AL habe ich gute Erfahrungen gemacht, AL ist auch als automatische Erweiterung betreff Suchpfad für Klassen/Methoden zu betrachten.

    Es lohnt sich jedoch, über die grundsätzliche Code-Verteilung nachzudenken, nicht nur aus Gründen der Performanze sondern auch hinsichtlich der Überschaubarkeit, Teamarbeit und agiler Softwareentwicklung.

    Hotti

    1. Den Autoloader benutze ich in PHP reichlich. Und die Datei ist eine externe Klassenbibliothek die wir nutzen möchten.

      Was mich eben verwundert ist das verhältnis. Würde eine 20kb Datei eine Zeit von 1 brauchen, würde ich eine 60kb Datei bei einer Zeit von 3 schätzen und nich von 200. Das verhältnis passt halt nicht.

      Das APC hab ich mir jetzt mal angeguckt. Muss mich korrigieren, hab mich da doch schonmal eingelesen. Das können wir leider nicht nutzen, da wir nur ein billig Webserver haben und da nichts selber installieren können :(.

      Danke für eure Hilfe

      Gruß
      das morgige Burzeltag Kind
      T-Rex

      1. hi,

        Was mich eben verwundert ist das verhältnis. Würde eine 20kb Datei eine Zeit von 1 brauchen, würde ich eine 60kb Datei bei einer Zeit von 3 schätzen und nich von 200. Das verhältnis passt halt nicht.

        Idee für weitere Annalüsen: Das Einlesen vom Kompilieren trennen. Also den Bench mal nur für das Einlesen machen, Einlesen der zu vergleichenden Dateien als text/plain.

        Kompilieren: Das geht dann mit der PHP-Funktion eval. Hier mein Ansatz:

          
        // Source einlesen und zu Code machen  
        function src2code($filename){  
        	global $srcpath;  
        	$fh = fopen("$srcpath/$filename", "r") OR ex("Can't read the SrcFile '$srcpath/$filename'");  
        	$src = fread($fh, filesize("$srcpath/$filename"));  
        	eval($src) or ex("The Class-Source '$srcpath/$filename' doesn't return a true value");  
        }  
        
        

        Hinweis dazu: Die Class-Datei enthält nur PHP-Code, also keine umschließenden <?php ?> Tag's. Die letzte Zeile in der Class-Datei lautet return 1;, damit kannst Du eval abfragen, ob das Kompilieren "durchgegangen" ist (ansonsten Exception, s.o.).

        das morgige Burzeltag Kind

        Das Datum stimmt sowieso nicht, ein Jahr hat nicht immer 365 Tage. Wenn Du's genauer haben möchtest, zähle die Tage ;)

        Hotti

        --
        Wenn ich in Hanau wohnen würde, hieße mein Auto HU GO 1957. Aber die MZ TS 250 ist auch ein schönes Mopped.
  3. Erstmal Danke an euch zwei für die Hilfe.

    Das ganze nimmt aber an Kurriosität zu... Hab mir die Dateien mal mit nach Hause genommen und hier nochmal den gleichen test gemacht. Da mein Rechner besser ist als in der Arbeit wird alles schneller ausgeführt, aber die Zeiten stehen jetzt in einer Relation zueinander.

    Am Montag werde ich in der arbeit weitere tests machen.
    Bis dahin schönes Wochenende

    @Hotti

    Gruß
    das Geburtstagskind, das HEUTE Geburstag hat!!!
    T-Rex

    1. Tach!

      Das ganze nimmt aber an Kurriosität zu... Hab mir die Dateien mal mit nach Hause genommen und hier nochmal den gleichen test gemacht. Da mein Rechner besser ist als in der Arbeit wird alles schneller ausgeführt, aber die Zeiten stehen jetzt in einer Relation zueinander.

      Beachte bitte bei deinen Tests, dass der Cache vom Datei-/Betriebsystem mitspielt und Messeregebnisse besonders im Wiederholungsfall beeinflusst.

      Wenn du die Dateigröße im Verdacht hast, dann erstell mal eine, die nur aus PHP-Kommentaren besteht - oder zwei Versionen, eine mit einem großen Kommentar und eine mit vielen kleinen Kommentaren. Ändert das etwas am Ergebnis?

      dedlfix.

  4. Hi,

    Welche Ursachen kann ein derartig langsames laden haben und wie kann ich es beschleunigen?

    Platte mal defraggen …?

    MfG ChrisB

    --
    RGB is totally confusing - I mean, at least #C0FFEE should be brown, right?
  5. Moin,

    also wir haben die Ursache gefunden.
    Das Framework besteht aus zwei Dateien (zwei Klassen). Nennen wir sie mal a und b. Die Datei a includiert die Datei b, wenn die Klasse von Datei b noch nicht geladen wurde. Im code sieht das wie folgt aus:

    if(!class_exists('KLASSE')) {  
      //-- include Datei b  
    }
    

    An der Stelle hat Sven natürlich recht, hier wird Code ausgeführt. In meiner überheblichen Art hätte ich jedoch niemals gedacht dass hier ein Problem sein könnte. Zumal meine ersten Tests hier keinen Zeitfresser ausmachten, aber da hab ich wohl unsauber getestet.
    Ich konnte die Funktion class_exists als Zeitfresser ausmachen. Aber nur in unserem richtigen System. Das System benutzt nämlich die tolle funktion __autoload. Diese wiederum haben wir mit ein wenig Logik versehen. Die sucht in Verzeichnissen nach einer Klasse. (nebenbei, die aufgepimpte Autload funktion sollte ich generell mal vorstellen)
    Was ich nicht wusste ist das class_exists() die __autoload funktion auslöst, wenn es die Klasse nicht gefunden hat. Unsere __autoload funktion sucht dann in diversen Verzeichnissen nach einer bestimmten Datei und liefert am Ende false zurück, da diese Datei nicht unserer Struktur entspricht. Und dieser Suchvorgang dauert eben ein wenig.

    Eigentlich müsste ich die __autload funktion umbauen, so dass aufrufe von class_exists sofort mit false quitiert werden. Ich habe jedoch erstmal das if(!class_exists()) aus dem Code genommen. Das brauchen wir an der Stelle nicht.

    Danke für eure Hilfe!

    Gruß
    dino_exists( T-Rex )

    1. Moin!

      if(!class_exists('KLASSE')) {

      //-- include Datei b
      }

      
      >   
      > An der Stelle hat Sven natürlich recht, hier wird Code ausgeführt. In meiner überheblichen Art hätte ich jedoch niemals gedacht dass hier ein Problem sein könnte. Zumal meine ersten Tests hier keinen Zeitfresser ausmachten, aber da hab ich wohl unsauber getestet.  
      > Ich konnte die Funktion class\_exists als Zeitfresser ausmachen. Aber nur in unserem richtigen System. Das System benutzt nämlich die tolle funktion \_\_autoload. Diese wiederum haben wir mit ein wenig Logik versehen. Die sucht in Verzeichnissen nach einer Klasse. (nebenbei, die aufgepimpte Autload funktion sollte ich generell mal vorstellen)  
        
      Lieber nicht. Du hast einen Performancefresser als Autoloader gebaut, sowas will man vermeiden.  
        
      Der aktuelle Stand ist, dass man jeglichen Code in PHP kompatibel zu "PSR-0" macht und dann irgendeinen PSR-0-Autoloader verwenden kann - die Frameworks bringen alle schon einen mit.  
        
      Ein guter Autoloader macht nicht zuviel. Er lädt die Klasse nach genau einem Schema, oder er scheitert. Ob er ran darf, wird so billig wie möglich entschieden - PSR-0-Autoloader reagieren auf ein definiertes Prefix im Klassennamen, sonst gucken sie gar nicht erst im Dateisystem. Wenn er scheitert oder nicht ran durfte, darf das nächste Schema ran. Mehr als ein Schema zu haben ist allerdings ein Zeichen für Überarbeitungsbedarf aufgrund von veraltetem Code.  
        
      Solchen veralteten Code lädt man vermutlich am sinnvollsten über einen Classmap-Autoloader, d.h. man hat ein Array mit "Klassenname" => "pfad/dateiname.php" drin.  
        
      
      > Was ich nicht wusste ist das class\_exists() die \_\_autoload funktion auslöst, wenn es die Klasse nicht gefunden hat. Unsere \_\_autoload funktion sucht dann in diversen Verzeichnissen nach einer bestimmten Datei und liefert am Ende false zurück, da diese Datei nicht unserer Struktur entspricht. Und dieser Suchvorgang dauert eben ein wenig.  
        
      class\_exists hat zwei Parameter.  
        
      Andererseits: Warum werden in eurem Code nicht ALLE Klassen per Autoloader geladen? Dann muss man solches Gehampel nicht mehr tun, weil die Dateidefinition nur dann geladen wird, wenn die Klasse bei ihrer ersten Verwendung unbekannt war.  
        
       - Sven Rautenberg
      
      1. Du hast einen Performancefresser als Autoloader gebaut...

        Hab ich nicht! Vielleicht sollte ich doch mal vorstellen? :D

        Andererseits: Warum werden in eurem Code nicht ALLE Klassen per Autoloader geladen? Dann muss man solches Gehampel nicht mehr tun, weil die Dateidefinition nur dann geladen wird, wenn die Klasse bei ihrer ersten Verwendung unbekannt war.

        Weil wir keine Lust haben ein Framework mit 20-30 Dateien so um zu bauen, dass es mit unserem autoload funktioniert. Generell befolge ich die goldene Regel "don't touch a running system".
        Wenn sich die Autoren schon die mühe machen in jede Datei bzw. in die Hauptdatei 20 Include Befehle rein zu machen oder sogar einen eigenen autoload benutzen, wieso sollte ich das auseinander reißen? - ich bin mir der Ironie bewusst diesen Satz in diesem Thread zu benutzen, aber bis jetzt ging das immer gut.

        Gruß
        der mit dem geilsten Autloader der Welt
        T-Rex

      2. class_exists hat zwei Parameter.

        Wer lesen kann ist klar im Vorteil :(

        Gruß
        der der noch am lesen üben ist
        T-Rex