Runtime Comparison для PHP приложений
Очень часто в моей работе приходится сравнивать время выполнения того или иного кода с целью выбора наиболее оптимального решения, и каждый раз я писал небольшой обработчик с расчётом микровремени (microtime), после чего заносил все результаты в какую-нибудь таблицу Excel и вручную рассчитывал минимальное, максимальное и среднее время выполнения…
Для решения этой тривиальной задачи был выпущен пакет «Runtime Comparison», позволяющий сравнивать время выполнения кода без лишних затрат на разработку — просто устанавливаете зависимость и вызываете метод сравнения, передавая проверяемые варианты в качестве аргументов.
Установка
Проще всего установить пакет при помощи пакетного менеджера Composer:
composer require dragon-code/runtime-comparison --dev
И всё, пакет готов к работе.
Использование
Так как вся нужная информация выводится в консоль, то лучше вызывать данный код через консоль хоть через команды используемого Вами фреймворка, хоть напрямую через вызов файла, например, php handler.php
.
use DragonCode\RuntimeComparison\Comparator;
(new Comparator())->compare(
fn () => /* some code */,
fn () => /* some code */,
);
(new Comparator())->compare([
fn () => /* some code */,
fn () => /* some code */,
]);
(new Comparator())->compare([
'foo' => fn () => /* some code */,
'bar' => fn () => /* some code */,
]);
Передавать можно неограниченное количество аргументов.
Все переданные колбэки будут вызываться строго в указанном порядке. Если Вы хотите явно определить имена, то можете в метод compare
передать ассоциативный массив, где в качестве ключа будет указано название проверяемого функционала.
Пример результата выполнения
----- ------------------- -------------------
# 0 1
----- ------------------- -------------------
1 0.011713027954102 0.015522003173828
2 0.014931917190552 0.015424013137817
3 0.015513896942139 0.014975070953369
4 0.015083789825439 0.014898061752319
5 0.014750003814697 0.014961004257202
6 0.015435934066772 0.015391111373901
7 0.015177965164185 0.014806985855103
8 0.014681816101074 0.01552677154541
9 0.014717102050781 0.015773057937622
10 0.015694856643677 0.014908075332642
----- ------------------- -------------------
min 0.011713027954102 0.014806985855103
max 0.015694856643677 0.015773057937622
avg 0.014770030975342 0.015218615531921
----- ------------------- -------------------
winner loser
----- ------------------- -------------------
Количество итераций
По-умолчанию каждый колбэк проходит 10 итераций, но Вы можете задать своё количество вызывав метод iterations
:
use DragonCode\RuntimeComparison\Comparator;
(new Comparator())
->iterations(5)
->compare(
fn () => /* some code */,
fn () => /* some code */,
);
В случае если переданное значение будет меньше единицы, то скрипт будет использовать значение »1».
Пример результата выполнения
----- ------------------- -------------------
# 0 1
----- ------------------- -------------------
1 0.011653184890747 0.01565408706665
2 0.015084981918335 0.015007972717285
3 0.015398025512695 0.014491081237793
4 0.015589952468872 0.015861034393311
5 0.014101028442383 0.015037059783936
----- ------------------- -------------------
min 0.011653184890747 0.014491081237793
max 0.015589952468872 0.015861034393311
avg 0.014365434646606 0.015210247039795
----- ------------------- -------------------
winner loser
----- ------------------- -------------------
Округление значений
По-умолчанию скрипт не округляет результаты замеров, но Вы можете указать количество символов после запятой, до которых может производиться округление:
use DragonCode\RuntimeComparison\Comparator;
(new Comparator())
->roundPrecision(4)
->compare(
fn () => /* some code */,
fn () => /* some code */,
);
Пример результата выполнения
----- -------- --------
# 0 1
----- -------- --------
1 0.0112 0.015
2 0.0147 0.0155
3 0.0153 0.0153
4 0.0157 0.015
5 0.0154 0.0158
----- -------- --------
min 0.0112 0.015
max 0.0157 0.0158
avg 0.0144 0.0153
----- -------- --------
winner loser
----- -------- --------
Вывод только итоговой информации
В случае если Вы проверяете скорость выполнения при большом количестве итераций или просто не хотите смотреть на подробную статистику времени выполнения по каждой итерации, Вы можете вызвать метод withoutData
, который позволит скрыть её, отобразив в конечном итоге только суммарную информацию:
use DragonCode\RuntimeComparison\Comparator;
(new Comparator())
->withoutData()
->compare([
'foo' => fn () => /* some code */,
'bar' => fn () => /* some code */,
]);
Пример результата выполнения
----- ------------------- -------------------
# 0 1
----- ------------------- -------------------
min 0.011653184890747 0.014491081237793
max 0.015589952468872 0.015861034393311
avg 0.014365434646606 0.015210247039795
----- ------------------- -------------------
winner loser
----- ------------------- -------------------
Расчёт победителей
Победители рассчитываются в следующем порядке:
Если среди средних арифметических значений есть отличия, то победитель определяется по нему, иначе:
Если среди максимальных значений есть отличия, то победитель определяется по нему, иначе:
Если среди минимальных значений есть отличия, то победитель определяется по нему, иначе:
Все элементы отмечаются победителями.
Заключение
Теперь сравнивать время выполнения кода стало значительно проще и быстрее, и можно не тратить время на реализацию данного функционала