Jump to content
  • 0

Как измерять время выполнения скрипта


Kiar25
 Share

Question

Это статья написана для тех кто только начал изучать PHP. Здесь будет рассказано, как профилировать свой код или если сказать по русски, как измерить скорость его работы.

Задача - нужно перед началом работы кода поставить временную метку, и после окончания поставить временную метку. Посчитать разницу между конечной и начальной точкой отсчета и вывести результат.

Поехали :lol:

Для этого мы будем использовать функцию microtime()

<?php
echo microtime(); // Выведет что то наподобие этого - 0.48441300 1212042171
?>

По умолчанию эта функция выводит строку "микросекунды секунды". Для нашего измерения нам нужно поменять их местами, чтобы было "секунды.микросекунды". И сделать наш код универсальным для простого и приятного дальнейшего использования.

Для этого сделаем класс с двумя методами start и finish, как не трудно догадаться это будет начальное и конечное наше измерение, причем метод finish будет показывать нам уже готовый результат.

<?php
// Создаем наш класс
class Speed {
// Создаем два свойства нашего класса
static private $st;
static private $fin;
// Создаем метод, который ставит начальную точку и переводит ее к виду "сек.микросек"
static public function start(){
$start_arr = explode(' ', microtime());
self::$st = $start_arr[1].substr($start_arr[0], 1);
return self::$st;
}
// Создаем метод, который подсчитывает сколько прошло времени
static public function finish(){
$finish_arr = explode(' ', microtime());
self::$fin = bcsub(($finish_arr[1].substr($finish_arr[0], 1)), self::$st, 6);
return self::$fin;
}

}

?>

Описание кода:

$st - начальная точка отсчета

$fin - конечная точка отсчета

static - позволяет нам обращаться к членам класса без объявления объекта, используя

оператор разрешения области видимости ::

Если член класс объявляется static то обращаться к нему через префикс $this-> нельзя

private - спецификатор доступа, который показывает что обращаться к члену класса можно

только внутри класса. Для вывода этого свойства, так как оно private, будет отвечать метод класса.

public - спецификатор доступа, который показывает что обращаться к члену класса можно вне класса, т.е любой созданный объект может обращаться к этому методу или свойству( public стоит по умолчанию и если написать просто function start() - она будет public)

self:: - обращение к статическому члену класса

microtime(), explode(), substr(), bcsub() - читайте здесь www.php.su

Как использовать:

Сохраняем под любым именем например speed.php

<?php
include_once('speed.php');
Speed::start();

// Ваш код

echo '
'.Speed::finish();
?>

Теперь вы сможете узнать что быстрее for или foreach, а может быть while. Где лучше объявлять переменную вне цикла или внутри. Кто быстрее регулярные выражения или просто строковые функции PHP и т.д.

Экспериментируйте :)

Link to comment
Share on other sites

12 answers to this question

Recommended Posts

  • 0

LOL :lol: ну ты выдал, может быть. Если такой умный предложи свое решение )) . Сравним результат.

Читай выше - статья для новичков, где люди могут почерпнуть что то для себя новое, если ты все знаешь зачем читаешь, а тем более критикуешь )) . Если критикуешь то предложи более лучшее решение :cool:

Посчитай скорость работы скрипта

<?php
echo 'Noob!'; // У меня получилось 0.000040 может это конечно и погрешность как ты говоришь)
?>

Link to comment
Share on other sites

  • 0
если ты все знаешь зачем читаешь, а тем более критикуешь ))

Потрясающую чушь вы счас спороли. Если вы не хотели, что-бы ваш труд кто-то читал, не нужно было его писать.

то предложи более лучшее решение

А я что сделал? microtime(true);

<?php

echo 'Noob!'; // У меня получилось 0.000040 может это конечно и погрешность как ты говоришь)

?>

Ну давайте разберемся, что это такое?

<?php

class Speed {
// Создаем два свойства нашего класса
static private $st;
static private $fin;
// Создаем метод, который ставит начальную точку и переводит ее к виду "сек.микросек"
static public function start(){
$start_arr = explode(' ', microtime());
self::$st = $start_arr[1].substr($start_arr[0], 1);
return self::$st;
}
// Создаем метод, который подсчитывает сколько прошло времени
static public function finish(){
$finish_arr = explode(' ', microtime());
self::$fin = bcsub(($finish_arr[1].substr($finish_arr[0], 1)), self::$st, 6);
return self::$fin;
}
}

class cTimer {
// Создаем два свойства нашего класса
private $start;
// Создаем метод, который ставит начальную точку и переводит ее к виду "сек.микросек"
public function __construct() {
$this->start = microtime(true);
}
// Создаем метод, который подсчитывает сколько прошло времени
public function finish(){
return microtime(true) - $this->start;
}
}


// замеряем скорость работы 1000 раз. так как ваш код
// не пригоден для использования одновременно, воспользуемся моим таймером
$timer = new cTimer();
for ($i=0; $i<1000; $i++) {
Speed::start();
Speed::finish();
}
echo "Ушло ".$timer->finish()." секунд
n";

// замеряем скорость работы 1000 раз.
$timer = new cTimer();
for ($i=0; $i<1000; $i++) {
$test = new cTimer();
$test->finish();
}
echo "Ушло ".$timer->finish()." секунд
n";

// замеряем скорость работы 1000 раз.
$timer = new cTimer();
for ($i=0; $i<1000; $i++) {
$start = microtime(true);
$start = microtime(true) - $start;
}
echo "Ушло ".$timer->finish()." секунд
n";
?>

Ушло 0.029629945755 секунд

Ушло 0.0140280723572 секунд

Ушло 0.00976610183716 секунд

Ваш таймер сам работает в 3 раза медленее чем мог бы. Я кстати, не вижу, где здесь округление после 6-го знака. Давайте посмотрим на полученый вами 0.00004с. еще раз.

0.00004×1000 = 0.04

Именно столько занял бы вывод надписи ?Noob? и подсчет времени на е? вывод 1000 раз. Но ведь холостой подсчет занимает 0.03! Получается вс?, что вы мериете с 6-м знаком полсе запятой ? чистой воды шум (тут пятый, и то 75% ? шум).

Катайся по полу дальше, но учитесь измерять время адекватно.

Link to comment
Share on other sites

  • 0

Да давайте разберемся, мне тоже стало интересно, что же это такое и кто же из нас прав. homm тебе 5 баллов за просчет моего кода, действительно молодец, я даже не задумывался что и откуда берется)) .

Как говорится истина рождается в споре и в вине. Спор есть жаль у нас с тобой вина нет :)

Ушло 0.029629945755 секунд

Ушло 0.0140280723572 секунд

Ушло 0.00976610183716 секунд

:)

Это вообще что то непонятное так как microtime() - может вывести только - число.ХХХХХХ , до шести знаков после запятой. Микро -6 степень )) если вы забыли. А здесь прям homm у тебя получились атомные часы )) - я конечно понимаю что нанотехнологии сейчас модно, но не настолько же)).

<?php

echo '<h4>Первый способ</h4>';
///////////////////////////////////
include_once('speed.php');
Speed::start();
for($i=0; $i<8; $i++)
{
$x = pow(10, $i);
for($k=0; $k < $x; $k++)
{

}
echo 'время - '.Speed::finish()." - количество итераций - $x
";

}

echo '<hr>';

echo '<h4>Второй способ</h4>';
////////////////////////////////////
$start = microtime(true);
for($i=0; $i<8; $i++)
{
$x = pow(10, $i);
for($k=0; $k < $x; $k++)
{

}
echo 'время - '.bcsub(microtime(true), $start, 6)." - количество итераций - $x
";
}

?>

Этот код выведет нечто такое:

Первый способ

время - 0.000050 - количество итераций - 1

время - 0.000090 - количество итераций - 10

время - 0.000135 - количество итераций - 100

время - 0.000355 - количество итераций - 1000

время - 0.002419 - количество итераций - 10000

время - 0.023018 - количество итераций - 100000

время - 0.237944 - количество итераций - 1000000

время - 2.380135 - количество итераций - 10000000

Второй способ

время - 0.000000 - количество итераций - 1

время - 0.000000 - количество итераций - 10

время - 0.000000 - количество итераций - 100

время - 0.000300 - количество итераций - 1000

время - 0.002300 - количество итераций - 10000

время - 0.022700 - количество итераций - 100000

время - 0.237200 - количество итераций - 1000000

время - 2.404000 - количество итераций - 10000000

Как видно если количество итераций не велико то время будет 0 сек, что не может быть правдой (если использовать microtime(true) - как и говорил эта вариация этой функции выводит более округленный результат). Да при увеличении итераций, мой способ отстает от более простого собрата , но мне кажется это все мелочи (все таки 10 000 000 итераций это круто :) ).

Может быть конечно это все и шум, только какой то он интересный :lol:

Link to comment
Share on other sites

  • 0
если использовать microtime(true) - как и говорил эта вариация этой функции выводит более округленный результат

Отнюдь. Как я уже показал, функция выдает значения с точностью(шумом) хрен знает какого знака после запятой. Результат искажает bcsub. Ну не знает она, сколько будет 1,35е-6 :lol: Убедтся в этом предлагаю следующей строчкой:

printf('время - %0.6f - количество итераций - %d

', microtime(true)-$start, $x);

Так-же предлагаю внести старт таймера в цикл:

echo  '<h4>Первый способ</h4>';
///////////////////////////////////

for($i=0; $i<8; $i++)
{
Speed::start();
$x = pow(10, $i);
for($k=0; $k < $x; $k++)
{

}
echo 'время - '.Speed::finish()." - количество итераций - $x
";

}

echo '<hr>';

echo '<h4>Второй способ</h4>';
////////////////////////////////////
for($i=0; $i<8; $i++)
{
$start = microtime(true);
$x = pow(10, $i);
for($k=0; $k < $x; $k++)
{

}
printf('время - %0.6f - количество итераций - %d
', microtime(true)-$start, $x);
}

Первый способ

время - 0.000043 - количество итераций - 1

время - 0.000014 - количество итераций - 10

время - 0.000025 - количество итераций - 100

время - 0.000139 - количество итераций - 1000

время - 0.001289 - количество итераций - 10000

время - 0.012958 - количество итераций - 100000

время - 0.129161 - количество итераций - 1000000

время - 1.289577 - количество итераций - 10000000

Второй способ

время - 0.000009 - количество итераций - 1

время - 0.000007 - количество итераций - 10

время - 0.000018 - количество итераций - 100

время - 0.000183 - количество итераций - 1000

время - 0.001287 - количество итераций - 10000

время - 0.012895 - количество итераций - 100000

время - 0.128976 - количество итераций - 1000000

время - 1.289643 - количество итераций - 10000000

Я не знаю как у вас получилось, что ваш вариаент быстрее, потому что даже ежу понятно что он медленее. Я надеюсь, вы, как и я, утанавливаете процессу апача максимальный приоритет и выключаете фоновую музыку? :)

Как видите, в любом измерении microtime(true) дает меньший результат, более соответствующий действительности и не содержит никаких проблем с точностью.

Так-же хочу обратить внимание на то, что первая итерация выполняется медленнее чем вторая (в вашем случае ? сильно). Это время на компиляцию класса.

Тем не менее все-же хочу сказать, что мерить одну или сто или любое другое количество итераций, которые занимают время менее чем процента от секунды ? это попытка измерить вес воздуха домашними весами. У PHP все-же многопотоковый интерпретатор, и довольно интелектуальная систеа сам по себе. Иногда там происходят различные сервисные функции (чистка памяти, например) которые влияют на результат. Это видно, например на 1000 итерациях. Если провести эксперимент еще раз, значения могут поменяться.

Link to comment
Share on other sites

  • 0

Спасибо homm - действительно интересный получился диалог, по крайней мере для меня. :o

Я делал класс используя статический метод - чтобы обращаться к нему без создания объекта, что бы выиграть время. Интересная функция bcsub() - всегда считал что функция для работы с повышенной точностью должна быть в разы лучше чем простой "-"

Как я понял, просмотрев полученные тобой данные, - и я прав отчасти и ты, поэтому жму твою руку... и удачи.

Но с этой bcsub() - придется разобраться :)

И все таки одного не могу понять

<?php
echo '<h3>Первый способ</h3>';
$start = microtime(true);
sleep(3);
echo microtime(true) - $start; // Выведет нечто такое - 2.9770121574402

echo '<h3>Второй способ</h3>';
include_once('speed.php');
Speed::start();
sleep(3);
echo Speed::finish(); // Выведет нечто такое - 2.977125

echo '<h3>Третий способ</h3>';
$start = microtime(true);
sleep(3);
echo bcsub(microtime(true), $start, 10); // Выведет нечто такое - 2.9746000000
?>

Откуда берутся следующие цифры в первом случае? Если microtime(true) - выводит только число.ХХХХ - четыре знака после запятой

Link to comment
Share on other sites

  • 0

Elendor - конечно это похвально сделать код и не парится, но :)

number_format() - форматирует число флоат

Что ты сделал - ты поставил точку отсчета и сделал его форматирование, и это полный бред. Что ты посчитал?

Посмотри наверх там все и так в двух строчках и все просто, проще знака "-" ничего нет :)

Link to comment
Share on other sites

  • 0

Все это прекрасно, только вот нафига такие заморочки с классами, объектами и.т.д...

Если эта статья для "новичка", то ИМХО классы для него "темный лес"...

Весь скрипт действительно можно реализовать 2-4 мя строчками (без всяких классов)...

<?php
$mtime = explode(" ", microtime());
$start_time = $mtime[1] + $mtime[0];

##############################
# Ваш скрипт
##############################


$mtime = explode(" ", microtime());
print "Страница сгенерирована за ".round((($mtime[1] + $mtime[0]) - $start_time), 5)." сек.";
?>

Link to comment
Share on other sites

  • 0

Для этого и писалось это все, чтобы немного дать понятия о классах новичкам. Тем более здесь показано как пользоваться статическими свойствами и методами.

Здесь на форуме очень много людей ищут уже готовые решения и не хотят думать самостоятельно, может быть такие рубрики дадут тот толчек для людей хотящих научится писать самостоятельно, а не списывать и использовать чужие скрипты.

Я уже много раз писал - нет предела совершенства. Одну и ту жу задачу можно решить многими спосабами, все зависит лишь только от знаний и фантазии человека, что впринципе эта рубрика и показала :)

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Answer this question...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. See more about our Guidelines and Privacy Policy