Тестирование скорости выполнения функции
В Delphi есть такой приятный оператор div - деление нацело. То есть 7 div 3 = 2, 7 mod 3 = 1. В PHP есть аналог mod - 7 % 3 = 1, а вот есть ли аналог div я постоянно забываю ![]()
Самое интересное, что алгоритм выяснения постоянно одинаковый. Я захожу на php.net/случайная_функция (кстати, удобнейшый вид вызова справки и самый простой способ добраться до мануала не выбирая версию online и язык), там нахожу php.net/manual/en/language.operators.arithmetic.php и ругаюсь, потому что аналога нет.
Казалось бы, Вова, что сложного написать floor($a/$b)? А вот нет, меня потянуло читать комментарии в которых часто есть хорошие советы и куски кода.
Там нашлась такая функция. Обещали, что она окажется очень быстрой
-
function div($x, $y) {
-
if ($x == 0) return 0;
-
if ($y == 0) return false;
-
return ($x - ($x % $y)) / $y;
-
}
Но, сами понимаете, что, когда функция выполняется доли секунды, тяжело на глаз определить, стало ли быстрее. Поэтому я быстро сделал класс для тестирования, используя который можно написать:
-
<?
-
-
// old good normal division
-
function div1($x, $y) {
-
if ($x == 0) return 0;
-
if ($y == 0) return false;
-
}
-
-
// potentially fast function
-
function div2($x, $y) {
-
if ($x == 0) return 0;
-
if ($y == 0) return false;
-
return ($x - ($x % $y)) / $y;
-
}
-
-
$timer = new Timer();
-
-
// test normal division
-
$timer->start();
-
for ($i=0; $i<100000000; $i++) { // yep, 100 million
-
$c = div1($a, $b);
-
if ($i % 1000000 == 1) $timer->keepAlive();
-
}
-
$timer->stop();
-
-
-
// test potentially fast function
-
$timer->start();
-
for ($i=0; $i<100000000; $i++) {
-
$c = div2($a, $b);
-
if ($i % 1000000 == 1) $timer->keepAlive();
-
}
-
$timer->stop();
-
-
?>
В итоге получаем:
Normal division: 159.965 seconds
New function: 148.095 seconds
То есть, в принципе, всё равно, что использовать, огромного прироста в скорости не наблюдается. Вывод: нечего заниматься глупостями, лучше бы я настроил кеширование в текущем проекте. Так что хватит читать блоги (кроме этого :)) - пора программировать.
Но в итоге получился маленький удобный класс для тестирования всяких потенциальных полезностей. Можно запускать сразу несколько таймеров.
-
<?
-
-
class Timer {
-
private $timer = false;
-
private $time = false;
-
public $keepAliveText = '<!-- -->';
-
-
function start() {
-
$this->time = false;
-
}
-
-
function stop() {
-
if ($this->timer==false) {
-
return false;
-
}
-
-
$this->timer = false;
-
-
return $this->getTime();
-
}
-
-
function getTime() {
-
}
-
-
function keepAlive() {
-
}
-
}
-
-
?>
Мне тоже кажется, что вот такой простой класс в тысячу раз лучше всякого рода профайлеров!
Хотя, в свое время, было много споров на тему доверия к замерам полученным твоим способом.
Я обычно оптимизирую, когда чувствую, что можно ускорить как минимум в 5 раз. Поэтому точность +/- 10% меня абсолютно не волнует. Оптимизация на несколько процентов - это удел даже не больших, а огромных приложений как Facebook и Yahoo. А там используются другие способы - на чистом PHP пишутся некритичные куски, а медленные и часто используемые переписываются на каком-то более низкоуровневом языке и подключаются модулями.
Я сижу под Linux и как-то в привычку уже вошло. Делаю one-liner:
time for i in `seq 1 10`; do php script.php > /dev/null; done
Где 10 - сколько циклов, script.php - твой скрипт или с ключом -r - тоже php one-liner.
Результат че-то типа этого:
real 0m10.058s
user 0m0.000s
sys 0m0.000s
Еще в xdebug есть профайлер, все никак не соберусь сделать про него пост
А насчет оптимизации... этим можно заниматься вечно, поэтому стОит оптимизировать то что реально тормозит. Мы например в inbox.lv кэшируем все что можно в локальные файлы, memcache и shared memory
Чувствую, я тоже пересяду на Ubuntu. Хочу многозадачности в PHP, а это работает только под Unix.
Никак, правда, не решусь, потому что люблю Office 2007 и свои утилитки на Delphi.
мда... Кто Вас учил проверять скорость выполнения функций? Вы бы еще system в цикл поставили бы.
Вам не кажется что два rand и одно условие в цикле сводят всю Вашу проверку на нет?
Попробуйте убрать оба рандома (ограничьтесь константами) и проверку. Так, чтобы в цикле было только выполнение функции div.
А keepalive - так это вообще шедевр... Про то, что такого рода тесты надо проводить ТОЛЬКО в консоли и на не загруженной машине я вообще молчу.
Вообщем, когда все это будет проделано - тогда и только тогда можно будет наблюдать более менее чистую разницу в производительности (чтобы она была совсем чистой надо дополнительно замерять скорость выполнения пустого цикла). А до тех пор все Ваши тесты и проверки не имеют ровным счетом никакого смысла.
Я писал, что в большинстве случаем для меня важно, когда скорость выполнения различается хотя бы в 5 раз.
Поэтому то, что вы написали, важно, но показывает невнимательность к предыдущим комментариям.
Проверил в Perl. Если проверять конкретно операцию целочисленного деления то div2 быстрее больше чем в 5 раз (в среднем быстрее на 650%) по сравнению с POSIX::floor. Так может Вы таки сперва проверите, а потом уже будете писать про различия в разы?
Я согласен, тестирование скорость такого деления не особо важно, потому что врятли у Вас будет столько операций деления в программе. Но тогда с другой стороны зачем тогда размещать пост? И зачем вообще изначально тестировать неправильно? Вы же не для себя пишите, так потрудитесь проработать код как следует, прежде чем его постить. ИМХО.
Не думал, что это может ТАК сильно повлиять. Что ж, посыпаю голову пеплом.