Unerklärliches Problem mit der Scriptausführungszeit

xtramen01

Erfahrenes Mitglied
Hallo Leute,
ich habe ein mir unerklärliches Phänomen durch Zufall entdeckt.
Mir kam mein Script ein wenig träge vor, da habe ich mal ein wenig gemessen.

Szenario 1:

PHP:
/*
 *  Frontcontroller initialisieren, der alle weitere Aktionen Kontrolliert
*/
define('START_PARSE_TIME', microtime(true));

	new mainApplication;

	define('PARSE_TIME', microtime(true) - START_PARSE_TIME);

	echo round(PARSE_TIME, 3) . ' sekunden';

Da kommt eine Zeit von ca. 1,8 Sekunden raus.
Mir unerklärlich, denn selbst wenn die Klasse mainApplication leer ist, bzw. lediglich ein leeres Construct hat, ist die Ausführungszeit des Scriptes so hoch.

Szenario 2:

PHP:
    class mainApplication{
    	
		public function __construct(){
			
		       define('START_PARSE_TIME', microtime(true));
			

                        //Hier dazwischen werden Template Engine, Datenbank, Content usw. initialisiert
			
			define('PARSE_TIME', microtime(true) - START_PARSE_TIME);
			echo round(PARSE_TIME, 3) . ' sekunden';			
			
		}
     

    }

Hier kommt eine Zeit von 0,07 Sekunden raus.

Hat da jemand eine Erklärung dafür? Mir ist es absolut schleierhaft. Oder habe ich einen Denkfehler bei der Messung.

Gruss
 
Evtl. hast du vergessen, dass der Webserver noch Zeit zum ausliefern der Daten benötigt. Häufig liegt es auch daran, dass der Webserver die Anzahl der Bytes aus dem Content nicht liefert (HTTP-Header Content-Length). Wenn du mit Output-Bufferung erst mal den kompletten Inhalt abfängst, dann mit ob_get_contents() den gepufferten Inhalt in eine Variable legst, dann strlen() auf die Variable machst, kannst du ganz einfach den HTTP-Header senden, bevor du mit echo den Inhalt an den Client sendest.

Wenn du mehr Interesse an der Thematik hast, lege ich dir mal das Stichwort "Profiling" ans Herz und verweise mal auf mein Tutorial zum Thema: http://www.tutorials.de/content/206-programm-flaschenhaelse-php-mit-xdebug-finden.html
 
Nochmal ich.
Ich glaube ich habe den "Flaschenhals" gefunden.
Und zwar habe ich gewisse Konfigurationsparameter wie DB Zugangsdaten, Template Name, Pfade usw. in ein einer ini Datei gespeichert. Wenn ich folgende Klasse weg lasse dann rennt das Script auf einmal.
Kann das wirklich sein das es fast 2 Sekunden benötigt, bzw. die ganze Anwendung so träge wird dadurch?

Hie mal die Klasse:

PHP:
<?php 
    
    class Config{
    	
		private $ini_file = array();

        function __construct(){
        	$this->ini_file = parse_ini_file('Config/Settings.ini', true);    
        }
    
        public function get($value){
            
            $string = str_replace(':', '', $value);
            $string = explode('_', $string);
            
            $group = $string[0];
            $key = $string[1];
            
            
            return $this->ini_file[$group][$key];
        }
    }
        
?>

Ich bin für jeden Tip dankbar :-)

Gruß
 
Hmm, wenn die Settings.ini recht umfangreich ist, wäre es eine Erklärung für die Trägheit. Kannst du es auf den parse_ini_file() Call eingrenzen? Wie sieht es mit Kommentaren in der Datei aus? Sind das viele? Wie groß ist die Datei?

Hier hat einer einen Trick gepostet, wie APC (ein Opcode-Cache) das Ganze etwas beschleunigen kann:

PHP:
function parse_ini_file_ext ($file, $sections = null) {
    ob_start();
    include $file;
    $str = ob_get_contents();
    ob_end_clean();
    return parse_ini_string($str, $sections);
}

EDIT: Ansonsten hätte ich noch ne andere Idee, aber erstmal schau, ob es tatsächlich parse_ini_file() ist.

EDIT2: Ich bekomme einen Schnaps von dir (4444 Posts ;-))

EDIT3: Lass mal das TRUE bei parse_ini_file() weg, du brauchst die Sections offenbar eh nicht.
 
Zuletzt bearbeitet:
So.
Erstmal ein Schnaps für Dich....Prost!! :-)

Ich habe nun Xdebug installiert und mit KCachegrind mal ein wenig Analysiert und ich glaube den Übeltäter gefunden zu haben.
Lokal läuft das Script zwar in 0.2 Sek durch, aber das ist denke ich normal.

Weniger normal finde ich die Calls meiner Autoload Klasse.
Da werden mit einem Scriptdurchlauf, sage und schreibe 4558 Aufrufe gestartet.

Und zwar geht es um diesen Part:

PHP:
        protected function getClassMap(){

            if (!empty($this->classmap)) {
                return $this->classmap;
            }

            if ($this->useCache && file_exists($this->getClassMapCacheFile())) {
                $this->classmap = include($this->getClassMapCacheFile());
                return $this->classmap;
            }
           
            foreach ($this->directories as $_dir) {
            
                $it = new \RecursiveDirectoryIterator(realpath($_dir));
                foreach (new \RecursiveIteratorIterator($it) as $_key => $_value) {
                    if ($_value->isFile()) {
                    
                        $custom_file = str_replace('Core', '', $this->getNamespaced($_key, $_dir));
                        $custom_file = 'Custom' . $custom_file;
                        $custom_file = str_replace('\\', DIRECTORY_SEPARATOR, $custom_file);
                        
                        if(file_exists(realpath($custom_file))){
                            $this->classmap[$_value->getFilename()] = realpath($custom_file);
                            $this->classmap[$this->getNamespaced($_key, $_dir)] = realpath($custom_file);
                        }else{
                            $this->classmap[$_value->getFilename()] = realpath($_key);
                            $this->classmap[$this->getNamespaced($_key, $_dir)] = realpath($_key);                            
                        }
                        
                    }
                }
            }
            
            return $this->classmap;
        }




        protected function getNamespaced($filename, $baseDir){
            return str_replace(DIRECTORY_SEPARATOR, '\\', str_replace($baseDir.DIRECTORY_SEPARATOR, '', $filename));
        }

getNamespaced wird dabei 4558 x von getClassMap aufgerufen.
Ist das normal? Findest Du da einen Fehler?

Gruss und Danke für die Hilfe!
 
So ich habe die Classmaps nun mal in einen Cache verfrachtet.
Das Script rennt nun wie Schumi in seinen besten Zeiten. Allerdings ist die Cache Datei 600 KB groß und es werden ja trotzdem alle Files die im kompletten Projekt sind, gescannt. Ich schaue mal wie ich das am besten hinbekomme. Danke und einen guten Rutsch!
 
Freut mich, das du dein Problem finden konntest, dann hat sich das Tutorial gelohnt :-)

Auf die Idee mit dem Cache bin ich auch gekommen, allerdings für die parse_ini_file()-Variante. Da serialisierte Daten am schnellsten geladen werden, hätte man mittels stat() erst das Ini-File auf Modification-Time und anschließend eine Cache-Datei für serialisierte Array-Daten geprüft und ggf. das Cache-File aktualisiert. Ich bin mir aber nicht sicher, ob das so viel raus reißt.

Problematisch an Caches ist die Aktualisierung. Wenn du an deinem Klassen-Pfad was änderst, musst du das Cache-File auch aktualisieren lassen. Das vergisst man im Eifer des Gefechts dann ganz gern. Man kann es zwar automatisieren, aber dann wird der Code der für das automatische Aktualisieren notwendig ist evtl. langsam. Ein zweiseitiges Schwert.

Dir auch nen guten Rutsch!
 
xtramen01 hat gesagt.:
Allerdings ist die Cache Datei 600 KB groß und es werden ja trotzdem alle Files die im kompletten Projekt sind, gescannt.

Wenn du den Cache aktivierst, sollte genau das eigentlich nicht mehr passieren.

Die 600 kB sind nicht die Welt, aber bietet der Autoloader nicht vielleicht auch was an, was keine Classmap nutzt? So eine Art PSR-0-Schema?

- http://www.php-fig.org/psr/psr-0/

Diese getClassMap-Methode ist jedenfalls definitiv nicht dafür gedacht, ungecachet auf einem Produktivsystem zu laufen.

Vielleicht steht in der Doku zu der Software was dazu?

PS: Super, kcachegrind und so zu nutzen. :)
 
Zurück