PHP:
<?php
define('ITERATIONS', 1000);
if (!isset($argv[1])) {
die('$ php -f ' . __FILE__ . ' all' . "\n");
}
if ($argv[1] === 'all') {
passthru('php -f ' . $argv[0] . ' 1');
passthru('php -f ' . $argv[0] . ' 2');
passthru('php -f ' . $argv[0] . ' 3');
exit;
}
function test1(array $input)
{
for ($i = 0; $i < ITERATIONS; $i++) {
$output = '';
$first = true;
foreach ($input as $ky => $value) {
if ($first) {
$output = $value;
$first = false;
} else {
$output .= ', ' . $value;
}
}
}
return md5($output) . md5($i);
}
function test2(array $input)
{
for ($i = 0; $i < ITERATIONS; $i++) {
$output = '';
foreach ($input as $ky => $value) {
$output .= ', ' . $value;
}
$output = trim($output, ', ');
}
return md5($output) . md5($i);
}
function test3(array $input)
{
for ($i = 0; $i < ITERATIONS; $i++) {
$output = '';
foreach ($input as $ky => $value) {
if ($output === '') {
$output = $value;
} else {
$output .= ', ' . $value;
}
}
}
return md5($output) . md5($i);
}
$input = array();
$i = 0;
while($i < 5000) {
$i++;
$input[] = 'Das ist eine sehr lange Textzeile die hier eingefügt wird,
immer und immer wieder, bis genug Stoff im Array liegt.';
}
/* Run tests */
$start = microtime(true);
if ($argv[1] === '1') echo 'chck: ' . test1($input) . "\n";
if ($argv[1] === '2') echo 'chck: ' . test2($input) . "\n";
if ($argv[1] === '3') echo 'chck: ' . test3($input) . "\n";
printf("it/s: %d\n", (int) round(ITERATIONS / (microtime(true) - $start)));
echo 'mmry: ' . memory_get_peak_usage(), "\n";
echo "\n";
Code:
$ php -f benchmark.php all
chck: 30b68d9d3ccd7a456ad88f34aaaaf47aa9b7ba70783b617e9998dc4dd82eb3c5
it/s: 127
mmry: 2686648
chck: 30b68d9d3ccd7a456ad88f34aaaaf47aa9b7ba70783b617e9998dc4dd82eb3c5
it/s: 119
mmry: 3148552
chck: 30b68d9d3ccd7a456ad88f34aaaaf47aa9b7ba70783b617e9998dc4dd82eb3c5
it/s: 127
mmry: 2686596
it/s = iterations per second
Die Resultate schwanken. test1 und test3 (die Lösungen ohne trim) sind beim geposteten Testaufbau auf meinem Rechner tendenziell gleich schnell und tendenziell unsignifikant schneller als die Lösung mit trim. Sie verbrauchen außerdem weniger Speicher.
Aber: Je kleiner das Eingabe-Array, desto mehr holt trim auf. Bei einer Größe von 50 Einträgen ist trim in meinen Tests schneller.
Ich habe diverse halbgare Theorien dazu, kann es aber nicht wirklich erklären. Grob: Die nativen PHP-Funktionen sind in C implementiert und deshalb sehr schnell. Sie haben allerdings einen gewissen Overhead, der durch die „Datenübergabe“ an die C-Funktion und den Speicherverbrauch der C-Funktion selbst erzeugt wird. Je größer die Eingabedaten, desto größer dieser Overhead, desto größer vermutlich auch die Laufzeit.
Da C-Code aber massiv schneller ist als PHP-Code, ist die mit Abstand schnellste Lösung an dieser Stelle der Verzicht auf PHP-Konstrukte (for-Schleife, if-Bedingungen, …). Das heißt:
PHP:
function test4(array $input)
{
for ($i = 0; $i < ITERATIONS; $i++) {
$output = implode(', ', $input);
}
return md5($output) . md5($i);
}
Code:
chck: 30b68d9d3ccd7a456ad88f34aaaaf47aa9b7ba70783b617e9998dc4dd82eb3c5
it/s: 505
mmry: 3023888
Das wäre im Vergleich zu den Lösungen ohne Funktionsaufrufe die
„Time-Memory Tradeoff“-Lösung. Geringere Laufzeit, höherer Speicherverbrauch.
Die fällt in dem Szenario, in dem direkt die DB-Resultate verarbeitet werden, aber flach, da sie ein Array mit Eingabedaten verlangt.
Mein Favorit unter den Lösungen mit geringem Speicherverbrauch ist test1. Die Lösung verlässt sich nicht darauf, dass die zu füllende Variable nur beim ersten Durchlauf einen bestimmten Wert hat. Das macht sie vom Schema her allgemeiner einsetzbar.
Das Fazit ist aber: Traut keinem Benchmark, den ihr nicht selbst gefälscht habt. ;)