Thursday, April 23, 2009

Efficient Code - PHP

I guess I'm a nut about execution speed. Well, not if it gets in the way of clarity, but I hate writing slow code.

But . . . always a 'But' . . . it's hard to know what is slow and what isn't. Seems like it should be easy, but I never know until I measure.

Here's an example:

The PHP manual page for preg_split() says that you shouldn't use it unless you need the flexibility of regular expressions. You should use explode() or str_split(), because they are simpler and therefore faster. I believed that.

Then I thought I'd like to see how much faster, so I wrote a couple of loops which split a comma separated string with both preg_split() and explode() to see how much I was really losing.

Here's are the average times of 10 passes through 1,000,000 splits using each:
preg_split() - 3.51239209175 seconds
explode() - 4.33661820889 seconds

preg_split() is about 23% Faster than explode().

I'm still not sure I believe it. Here's the code - so you can try it yourself.

And, please let me know if you see anything I did wrong.


$str = 'this, is , a , string, with , commas, in ,it';
$count = 1000000;
$passes = 10;
$times = array(xdebug_time_index());
$avg = array('preg' => array(), 'explode' => array(), 'map-explode' => array());
function dt($offset = 1)
{
global $times;
$last = count($times) - 1;
return $times[$last] - $times[$last - $offset];
} // end of dt()

for ($pass=0;$pass<$passes;$pass++) {
echo "Pass $pass\n";
$times[] = xdebug_time_index();
for ($i=0;$i<$count;$i++) {
$v = preg_split('/^\s*,\s*/', $str);
unset($v);
}
$times[] = xdebug_time_index();
$avg['preg'][] = dt();
echo "$count preg_split's(regx, str): " . dt() . "\n";

$times[] = xdebug_time_index();
for ($i=0;$i<$count;$i++) {
$v = array_map('trim', explode(',', $str));
unset($v);
}
$times[] = xdebug_time_index();
$avg['map-explode'][] = dt();
echo "$count array_map(trim, explode(',', str)): " . dt() ."\n";

$times[] = xdebug_time_index();
for ($i=0;$i<$count;$i++) {
$v = explode(',', $str);
unset($v);
}
$times[] = xdebug_time_index();
$avg['explode'][] = dt();
echo "$count explode(',', str): " . dt() ."\n";
}

echo "Averges\n";
foreach ($avg as $key => $ar) {
echo "$key average of $passes trials of $count splits: " . array_reduce($ar, create_function('$a,$b', 'return $a+$b;'), 0) / count($ar) . "\n";
}

No comments: