

Lässt sich die Performance verbessern, wenn ein mit explode() zu zerlegender String zuvor mit strpos() untersucht wird, ob er den von explode() verwendeten Delimiter enthält? Wir haben mehrere kleine Scripte erstellt und sie einem Benchmark-Test unterzogen.
Code:<?
$teilstring="f";
$gesamtstring="abcdefghijk";
for ($i=0;$i<10000;$i++){
$test=explode($teilstring,$gesamtstring);
}
?>
Erläuterung:
Der String abcdefghijk wird innerhalb einer for()-Schleife 10.000mal anhand des Delimiters f zerlegt.
Code:<?
$teilstring="k";
$gesamtstring="abcdefghijk";
for ($i=0;$i<10000;$i++){
$test=explode($teilstring,$gesamtstring);
}
?>
Erläuterung:
Der String wird gegenüber dem ersten Beispiel-Code nun anhand eines anderen Delimiters zerlegt.
Code:<?
$teilstring="m";
$gesamtstring="abcdefghijk";
for ($i=0;$i<10000;$i++){
$test=explode($teilstring,$gesamtstring);
}
?>
Erläuterung:
In diesem dritten Beispiel-Script wird der String anhand eines Delimiters zerlegt, den er nicht enthält.
Code:<?
$teilstring="f";
$gesamtstring="abcdefghijk";
for ($i=0;$i<10000;$i++){
if (strpos($gesamtstring,$teilstring)!=="false"){
$test=explode($teilstring,$gesamtstring);
}
}
?>
Erläuterung:
Das vierte Beispiel-Script ist eine Abwandlung des ersten Beispiel-Codes. Vor Ausführen der explode()-Funktion wird mit strpos() geprüft, ob der an explode() übergebene Delimiter im String enthalten ist.
Code:<?
$teilstring="k";
$gesamtstring="abcdefghijk";
for ($i=0;$i<10000;$i++){
if (strpos($gesamtstring,$teilstring)!=="false"){
$test=explode($teilstring,$gesamtstring);
}
}
?>
Erläuterung:
Dieser fünfte Beispiel-Code enthält gegenüber dem vorangegangenen Script den Delimiter an einer anderen Stelle im String.
Code:<?
$teilstring="m";
$gesamtstring="abcdefghijk";
for ($i=0;$i<10000;$i++){
if (strpos($gesamtstring,$teilstring)!=="false"){
$test=explode($teilstring,$gesamtstring);
}else{
$test[0]=$gesamtstring;
}
}
?>
Erläuterung:
In diesem sechsten Beispiel-Script enthält der zu zerlegende String den Delimiter nicht. Aufgrund der mit strpos() durchgeführten Prüfung auf Vorhandensein des Delimiters im String wird die explode()-Funktion nicht ausgeführt. Stattdessen wird der gesamte String an ein $test-Array übergeben, so dass der Code das gleiche bewirkt wie in unserem dritten Beispiel-Code.
| Requests per second (RPS) | Time per Request (TPR) | Vergleich | ||
| String enthält den Delimiter in der Mitte, ohne strpos() | 51.28 [#/sec] (mean) | 19.500 [ms] (mean) | 30.6% | 23.4% |
| String enthält den Delimiter am Ende, ohne strpos() | 50.75 [#/sec] (mean) | 19.703 [ms] (mean) | 29.3% | 22.6% |
| String enthält den Delimiter nicht, ohne strpos() | 63.05 [#/sec] (mean) | 15.859 [ms] (mean) | 60.6% | 37.7% |
| String enthält den Delimiter in der Mitte, mit strpos() | 39.26 [#/sec] (mean) | 25.469 [ms] (mean) | ||
| String enthält den Delimiter am Ende, mit strpos() | 39.31 [#/sec] (mean) | 25.438 [ms] (mean) | 0.1% | 0.1% |
| String enthält den Delimiter nicht, mit strpos() | 45.94 [#/sec] (mean) | 21.766 [ms] (mean) | 17.0% | 14.5% |
Am schnellsten ausgeführt wird das dritte Beispiel-Script, bei dem ohne vorangegangen Überprüfung mit strpos() der String anhand eines nicht in selbigem enthaltenen Delimiters zerlegt wird. Etwas langsamer sind die beiden Scripte, in denen der String den Delimiter enthält ohne vorherige Suche via strpos() zerlegt wird. Die drei Scripte, bei denen der String mit strpos() durchsucht wurde, sind deutlich langsamer - selbst, wenn der Delimiter nicht im String enthalten ist.
An der wievielten Stelle der Delimiter im String enthalten ist, scheint keine Auswirkungen auf die Ausführzeit zu haben. Bei einem String mit einer Länge von 10 Zeichen verschlechtert eine dem Zerlegen vorangestellte Suche mit strpos() deutlich. Doch wie verhält es sich bei längeren Strings? Wir führen einen Benchmark mit folgenden Scripten aus:
Lässt sich die Performance verbessern, wenn ein mit explode() zu zerlegender String zuvor mit strpos() untersucht wird, ob er den von explode() verwendeten Delimiter enthält? Wir haben mehrere kleine Scripte erstellt und sie einem Benchmark-Test unterzogen.
Code:<?
$teilstring="f";
$string="abcdefghijk";
$gesamtstring="";
for ($i=0;$i<20;$i++){
$gesamtstring.=$string;
}
for ($i=0;$i<10000;$i++){
$test=explode($teilstring,$gesamtstring);
}
?>
Erläuterung:
Innerhalb einer for()-Schleife wird String mit der Länge 200 Zeichen wird anhand eines im String enthaltenen Delimiters 10.000mal mit explode() zerlegt. Dabei findet vor dem Zerlegen keine Überprüfung statt, ob der String den Delimiter enthält.
Code:<?
$teilstring="m";
$string="abcdefghijk";
$gesamtstring="";
for ($i=0;$i<20;$i++){
$gesamtstring.=$string;
}
for ($i=0;$i<10000;$i++){
$test=explode($teilstring,$gesamtstring);
}
?>
Erläuterung:
Anders als im vorangegangenen Beispiel-Code enthält der mit explode() zu zerlegende String den Delimiter nicht.
Code:<?
$teilstring="f";
$string="abcdefghijk";
$gesamtstring="";
for ($i=0;$i<200;$i++){
$gesamtstring.=$string;
}
for ($i=0;$i<10000;$i++){
$test=explode($teilstring,$gesamtstring);
}
?>
Erläuterung:
Ein 2.000 Zeichen umfassender String wird anhand eines im String enthaltenen Delimiters 10.000mal mit explode() zerlegt.
Code:<?
$teilstring="m";
$string="abcdefghijk";
$gesamtstring="";
for ($i=0;$i<200;$i++){
$gesamtstring.=$string;
}
for ($i=0;$i<10000;$i++){
$test=explode($teilstring,$gesamtstring);
}
?>
Erläuterung:
Der gleiche String wie im vorangegangenen Beispiel wird anhand eines Delimiters zerlegt, der im String nicht vorkommt.
Code:<?
$teilstring="f";
$string="abcdefghijk";
$gesamtstring="";
for ($i=0;$i<20;$i++){
$gesamtstring.=$string;
}
for ($i=0;$i<10000;$i++){
if (strpos($gesamtstring,$teilstring)!=="false"){
$test=explode($teilstring,$gesamtstring);
}
}
?>
Erläuterung:
Ein String der Länge 200 wird innerhalb einer for()-Schleife 10.000mal via explode() zerlegt. Vor dem Zerlegen wird mittels strpos() geprüft, ob der Delimiter im String vorkommt. In diesem Beispiel ist das der Fall.
Code:<?
$teilstring="m";
$string="abcdefghijk";
$gesamtstring="";
for ($i=0;$i<20;$i++){
$gesamtstring.=$string;
}
for ($i=0;$i<10000;$i++){
if (strpos($gesamtstring,$teilstring)!=="false"){
$test=explode($teilstring,$gesamtstring);
}else{
$test[0]=$gesamtstring;
}
}
?>
Erläuterung:
Im Unterschied zum vorangegangenen Beispiel-Code enthält der String den Delimiter nicht. D.h., die Prüfung via strpos() wird durchgeführt, gibt false zurück und explode() wird nicht ausgeführt. Stattdessen wird - um das gleiche Ergebnis zu bewirken - der String $test[0] zugeordnet.
Code:<?
$teilstring="f";
$string="abcdefghijk";
$gesamtstring="";
for ($i=0;$i<200;$i++){
$gesamtstring.=$string;
}
for ($i=0;$i<10000;$i++){
if (strpos($gesamtstring,$teilstring)!=="false"){
$test=explode($teilstring,$gesamtstring);
}
}
?>
Erläuterung:
Ein 2.000 Zeichen umfassender String wird 10.000mal mittels explode() zerlegt. Vor dem Zerlegen wird mit strpos() sichergestellt, dass der String den Delimiter enthält, anhand dessen er zerlegt werden soll.
<?
$teilstring="m";
$string="abcdefghijk";
$gesamtstring="";
for ($i=0;$i<200;$i++){
$gesamtstring.=$string;
}
for ($i=0;$i<10000;$i++){
if (strpos($gesamtstring,$teilstring)!=="false"){
$test=explode($teilstring,$gesamtstring);
}else{
$test[0]=$gesamtstring;
}
}
?>
Erläuterung:
Der Delimiter ist - anders als im vorangegangenen Beispiel - nicht im String enthalten.
| Requests per second (RPS) | Time per Request (TPR) | Vergleich | ||
| String (200 Zeichen) enthält den Delimiter, ohne strpos() | 11.42 [#/sec] (mean) | 87.547 [ms] (mean) | 806.3% | 89.0% |
| String (200 Zeichen) enthält Delimiter nicht, ohne strpos() | 59.48 [#/sec] (mean) | 16.813 [ms] (mean) | 4620.6% | 97.9% |
| String (2000 Zeichen) enthält den Delimiter, ohne strpos() | 1.30 [#/sec] (mean) | 769.016 [ms] (mean) | 3.2% | 3.3% |
| String (2000 Zeichen) enthält Delimiter nicht, ohne strpos() | 28.01 [#/sec] (mean) | 35.703 [ms] (mean) | 2123.0% | 95.5% |
| String (200 Zeichen) enthält den Delimiter, mit strpos() | 10.07 [#/sec] (mean) | 99.281 [ms] (mean) | 699.2% | 87.5% |
| String (200 Zeichen) enthält Delimiter nicht, mit strpos() | 39.02 [#/sec] (mean) | 25.625 [ms] (mean) | 2996.8% | 96.8% |
| String (2000 Zeichen) enthält den Delimiter, mit strpos() | 1.26 [#/sec] (mean) | 795.203 [ms] (mean) | ||
| String (2000 Zeichen) enthält Delimiter nicht, mit strpos() | 17.86 [#/sec] (mean) | 56.000 [ms] (mean) | 1317.5% | 93.0% |
Die niedrigste Ausführzeit hat das Script, bei dem ein 200 Zeichen String mit explode() anhand eines Delimiters zerlegt wird, der nicht im String vorkommt. Am längsten dauerte bei dem durchgeführten Benchmark das Script, bei dem ein String der Länge 2.000 den Delimiter enthält und dies vor dem Zerlegen mittels strpos() überprüft wird.
In sämtlichen Beispielen kostete die Überprüfung mit strpos() unnötig Ausführzeit. In der Praxis eher selten vorkommende Fälle, bei denen Strings die Größe von 100kB und mehr haben, wurden nicht geprüft.
Anmerkung:
Die Tests wurden mit dem Apache HTTP server benchmarking tool ab auf einem im Februar 2012 nicht mehr dem Stand der Technik entsprechenden Server durchgeführt. Die RPS und TPR der getesteten PHP-Scripte sollten auf einem im Produktiv-Einsatz befindlichen Webserver deutlich besser sein.