Performance: preg_replace ist langsam!(?)

Neulich habe ich ja schon die Auswirkungen von Konstanten mit Arrays in Bezug auf Speicherverbrauch verglichen. Nun ist es wieder Zeit für neue Performance-Erkenntnisse. Dieses Mal habe ich mir das Thema „preg_replace ist langsam!(?)“ rausgesucht, da ich herausfinden wollte, wie „böse“ wirklich die preg-Funktionen in Hinsicht auf Performance sind.

Mit preg-Funktionen muss man, wenn es denn geht, sparsam umgehen, sowas lernt man als PHP-Programmierer gleich von Anfang an. In der offiziellen PHP-Dokumentation steht es ja auch bei so ziemlich jeder preg-Funktion dabei, dass man sie nach Möglichkeit nicht nur für einfache Vergleiche (z.B. Ist String X in String Y enthalten) oder einfache Ersetzungen (z.B. ersetze „Hallo“ mit „Auf Wiedersehen“) benutzen soll. Das ist auch richtig so, da die Funktionen mit den regulären Ausdrücken nun mal „gewichtiger“ als die einfachen String-Funktionen (z.B. strpos, str_replace, etc.) sind. Aber inwiefern wirkt es sich auf die Laufzeit des Skripts aus? Ist jede Verwendung von preg_replace schon ein Performance-Killer? Ich habe mal ein paar Tests gemacht, die so sicherlich nicht auf den Alltag abzubilden sind, aber die Perfomance-Unterschiede auf gewisse Art darstellen sollen.

Zum Testen nehme ich zwei kurze Skripte, die, wie oben schon erwähnt, nicht sehr realitätsnah sind, aber hier ihren Zweck erfüllen. Skript Nummer 1 verwendet die Funktion preg_replace, Skript Nummer 2 gibt sich mit str_replace zufrieden.

Skript 1 – preg_replace


ini_set("memory_limit", "180M");

$intTimeStart = time();

$intMax = 100;

$str = "Hallo %grausame% Welt";
$str2 = "";

for($i = 0; $i < $intMax; $i++) {
	$str2 = preg_replace("/%grausame%/i", "schöne", $str);
}



echo "\n\n" . memory_get_peak_usage() / 1024 / 1024 . " MB\n\n";
echo "\n\n" . time() - $intTimeStart . " s\n\n";

Skript 2 - str_replace


ini_set("memory_limit", "180M");

$intTimeStart = time();

$intMax = 100;

$str = "Hallo %grausame% Welt";
$str2 = "";

for($i = 0; $i < $intMax; $i++) {
	$str2 = str_replace("%grausame%", "schöne", $str);
}



echo "\n\n" . memory_get_peak_usage() / 1024 / 1024 . " MB\n\n";
echo "\n\n" . time() - $intTimeStart . " s\n\n";

Die Variable $intMax stellt die Anzahl an "Ersetzungen" dar. Hier sind nun die Ergebnisse, wenn die Zahl entsprechend gesetzt wird.

$intMax = 100

  Speicher in MB Laufzeit in Sekunden
preg_replace 0.0391 0
str_replace 0.0391 0

 

 

$intMax = 10000

  Speicher in MB Laufzeit in Sekunden
preg_replace 0.0391 0
str_replace 0.0391 0

 

 

$intMax = 100000

  Speicher in MB Laufzeit in Sekunden
preg_replace 0.0391 0
str_replace 0.0391 0

 

 

$intMax = 1000000

  Speicher in MB Laufzeit in Sekunden
preg_replace 0.0391 2
str_replace 0.0391 2

 

 

$intMax = 10000000

  Speicher in MB Laufzeit in Sekunden
preg_replace 0.0391 24
str_replace 0.0391 15

Interessante Ergebnisse! Da immer dieselben Strings behandelt werden, ist es nicht verwunderlich, dass der Speicherverbrauch immer gleich bleibt. Aber auch die Laufzeit ändert sich (bei diesem einfachen Beispielskript) erst ab einer (verdammt) hohen Anzahl an Funktionsaufrufen!

Hieraus kann man wohl erkennen, dass auch einfache preg_replace-Ersetzungen bei weitem nicht das ganze Skript ausbremsen. Dennoch ist es natürlich "guter Stil", wenn man bei einfachen String-Operationen einen Bogen um die preg-Funktionen macht.

Nachtrag

Da war ich wohl etwas vorschnell! :-) Ich habe eben die Test noch mal wiederholt und dabei eine viel größere Zeichenkette genommen. Die Funktionen bleiben identisch, allerdings habe ich den Quelltext der Startseite von RVI-Media genommen und lasse nun zum Test alle div-Elemente durch span-Elemente ersetzen.

$intMax = 100

  Speicher in MB Laufzeit in Sekunden
preg_replace 0.688 0
str_replace 0.664 0

 

 

$intMax = 1000

  Speicher in MB Laufzeit in Sekunden
preg_replace 0.688 0
str_replace 0.664 1

 

 

$intMax = 100000

  Speicher in MB Laufzeit in Sekunden
preg_replace 0.688 13
str_replace 0.664 6

 

 

Bei größeren Zeichenketten ist also schon bei weitaus weniger Durchläufen eine viel größere Diskrepanz zwischen den Funktionen zu spüren. Dennoch bleibt es dabei, dass es wirklich erst ab einer (sehr) großen Anzahl an Ersetzungen spürbar wird.

War dieser Artikel hilfreich für Sie?
[Gesamt: 0 Durchschnitt: 0]

3 thoughts on “Performance: preg_replace ist langsam!(?)

  1. Markus sagt:

    Wow ein Benchmark ohne microtime.
    Sachen wie 0 Sekunden im Vergleich zu 0 Sekunden oder 2 Sekunden zu 2 Sekunden sind wirklich sehr aufschlussreich!

  2. Naja, das war leider nicht so nuetzvoll… Koenntest du es bitte mit microtime widerholen? :)

  3. Ronald sagt:

    Hey Marco,

    aus heutiger Sicht würde ich es vermutlich auch mit Mikrosekunden benchmarken (einfach der nerdigen Nachfrager wegen ;P) aber soweit ich mich erinnere hat es sich einfach nicht gelohnt um (für mich persönlich) mit dem Gerücht aufzuräumen, dass das die preg_-Sachen ganz viel langsamer wären. Und ob ein str_replace nun bei 1000000 Ersetzungen 0.1 Sekunde schneller ist als ein preg_replace interessiert mich heute auch immer noch nicht sonderlich.
    Generell sollte man sich ja nicht auf irgendwelche Benchmarks aus dem Internet verlassen, die zu dem noch mit alten (PHP-)Versionen gemacht wurden, sondern bei Bedarf einfach in der eigenen entsprechenden Systemumgebung testen.
    Sollte ich mal wieder Benchmarks veröffentlichen, dann aber natürlich in Mikrosekunden, danke für den Hinweis!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *