О бенчмарках
В данной заметке мы обсудим наболевшую тему бенчмарков для различных языков программирования.
Содержание
Много копий было сломано на холиварах о том какой язык всех прекрасней, всех румяней и белее - зачастую стороны аргументируют свою позицию не различиями в архитектуре языков или их приспособленности к решению определенного класса задач, а при помощи синтетических тестов производительности, найденных на просторах интернета.
На мой взгляд бенчмарки можно разделить на 2 большие группы: внутриязычные и межязычные. Первые позволяют продемонстрировать особенности языка и подсказать наиболее оптимальный вариант решения задачи, положенной в основу бенчмарка. Второй тип тестов помогает подчеркнуть различия между языками и дает представление о том, что похожие на вид конструкции могут вести себя по-разному в зависимости от того на каком языке они написаны.
Однако, результаты бенчмарков никак не применимы к доказательству превосходства одного языка над другим и результаты даже технически корректных тестов не должны приниматься в учёт при выборе инструментов для работы, если только данная работа не заключается в решении задачи, использованной в бенчмарке. Что уж говорить о бенчмарках некорректных, примеры которых рассматриваются далее.
В этой статье мы подробно рассмотрим 2 бенчмарка, корректность которых вызывает большие вопросы. Приведенные далее результаты представляют собой среднее потребление ресурсов в течении 100 прогонов. Для замеров в Python
использовались функции memory_usage
из модуля memory_profiler
и perf_counter
из модуля time
.
1. Поиск простых чисел от Ivan Zahariev
Данный бенчмарк, посвящённый сравнению времени работы алгоритма поиска простых чисел, обладает некоторыми особенностями:
- Несмотря на то, что рассматривается один и тот же алгоритм, реализации его в различных языках заметно различаются.
- Алгоритмы оперируют самыми базовыми конструкциями языков и не используются стандартные библиотеки, а сами реализации не учитывают специфику работы конкретных языков.
- Метод замера времени работы весьма ненадёжен и также не учитывает особенности среды исполнения тестируемых языков.
Результат данного теста:
Язык | Время работы |
---|---|
PHP7 | 6.624 |
Python | 18.077 |
Итого по результатам исследования Ivan Zahariev
выходит, что PHP7
обгоняет Python
в 2.73
раза! Однако реализация Python
алгоритма не соответствует общепризнанным практикам, попробуем повторить тот же эксперимент, но с использованием лучшей реализации алгоритма поиска простых чисел.
Тест | Время работы (с) | Потребляемая память (МБ) |
---|---|---|
PHP7 (Ivan Zahariev) | 0.386102 | - |
Python (Ivan Zahariev) | 1.37092 | 230.768 |
Python (RWH) | 0.343201 | 139.353 |
Python (RWH numpy) | 0.0130783 | 47.793 |
Таким образом всего лишь использовав другую реализацию на чистом Python
мы получили, что предложенная Ivan Zahariev
начинает отставать, а если воспользоваться алгоритмом, использующим numpy
(общепризнанная библиотека Python
для численных расчетов) то и вовсе Python
начинает обгонять PHP7
в 29.5
раз! Однако не стоит ориентироваться на данный результат при выборе инструмента для работы - это просто цифры. Конечно, в численных расчётах хорошая реализация на Python
существенно быстрее реализации на PHP7
, но и для него существуют свои ниши.
Таким образом мы продемонстрировали, что хоть самокат и быстрее мотоцикла, если использовать лишь ножную тягу, но с включением зажигания картина несколько меняется.
2. Подсчёт спектральной нормы от benchmarkgame
Данный бенчмарк страдает теми же проблемами, что и прошлый, но и привносит несколько своих:
Чтобы подаваемый бенчмарк был принят он должен реализовывать заранее заданные функции в заранее заданном сценарии без возможности использования сторонних библиотек, таким образом уже этот факт не позволяет судить о производительности языков.
Различные сценарии запускаются не последовательно, а параллельно, при этом управление синхронизацией и порождение процессов исполнения отдано на откуп реализатору бенчмарка, что вносит неконтролируемые помехи в получаемые результаты, что окончательно лишает смысла весь эксперимент.
Результат данного теста:
Язык | Время работы |
---|---|
PHP7 | 37.94 |
Python | 188.83 |
Пока что PHP7
обгоняет Python
в 5
раз! Но вот как изменится картина, если использовать язык согласно принятым в нём практиках
Тест | Время работы (с) | Потребляемая память (МБ) |
---|---|---|
PHP7 (benchmarkgame) | 8.964616 | - |
Python (benchmarkgame) | 51.5159 | 29.1393 |
Python (NumpySpectralNorm) | 0.40539 | 278.843 |
После замены реализации алгоритма на реализацию, использующую numpy
, мы получили ускорение в 127(!)
раз относительно бенчмарка, используемого на главной странице benchmarkgame
. Если же сравнивать с реализацией на PHP7
то здесь Python
быстрее в 22
раза. Снова повторюсь, что на синтетические тесты нельзя опираться при выборе инструмента.
Использованный в проекте код доступен в github репозитории
В тестах использовался
Python 3.6.2
иPHP 7.1.9
.В тестах
PHP7
не проводились никакие изменения - код алгоритмов взят из обсуждаемых в статье бенчмарках. Если есть предложения по оптимизации этих алгоритмов, то их можно оформить в виде pull реквеста в github репозиторий . В этом случае статья будет обновлена, а контрибуторы упомянуты.В репозитории также присутствуют тесты, которые проверяют, что альтернативные алгоритмы дают такой же конечный результат.
Мне не удалось замерить реальное потребление памяти в
PHP7
, доработки приветствуются.