Я являюсь веб-разработчиком уже несколько лет и постоянно слежу за развитием событий в среде веб-разработки.
В ходе профессиональной деятельности мне удалось познакомиться с ворохом технологий, языков, библиотек, фреймворков и прочим.
Периодически задавая себе вопрос «так что же выбрать для постоянной работы именно для себя (какой язык, какой фреймворк)?» я начал изучать всеобъемлющий гугл на предмет сего ответа. И был, однако, удивлен, т.к. нужной мне информации не нашел. Все статьи скатываются до того, что все языки и фреймворки хороши, особенно для отдельных задач и нельзя сказать — кто победитель. Мол, хочешь знать ответ — попробуй всё и реши для себя сам.
С последним утверждением я полностью согласен, но мне не хватило бы простого субъективного ответа, я захотел цифр. Тогда придумал взять набор задач, чтобы сравнить языки программирования, а также фреймворки и их привычный функционал. Т.к. я работаю на PHP, первым делом начал с выбора фреймворков именно для этого языка. Сейчас протестированы: Yii2, Laravel5. Взяты именно они, т.к. являются самыми популярными фреймворками на PHP (да, Symfony, про тебя тоже помню).
Из других языков (и фреймворков) были взяты JS (NodeJS + SailsJS) и Ruby (Rails), т.к. с ними тоже был определенный уровень знакомства.
Сразу разъясню, почему были взяты именно эти языки/фреймворки.
Главная цель для меня — выбор технологий для разработки будущих проектов, как моих, так и компании, где я работаю. Конечно, субъективную оценку цифрами не обозначишь, поэтому в результирующих таблицах будут только количественные показатели. В целом, я пришел к выводу, что мне удобны php и ruby + обозначенные выше фреймворки примерно в одинаковой мере. А вот разработка на nodejs мне не показалась такой удобной, быстрой и клёвой.
Итак, тесты производительности определенных задач для языков:
Первый тест — генерация числа Пи с количеством итераций = 100000000.
Далее идет тест по генерации Множество Мандельброта.
После — генерация экспоненты с помощью самого языка, а также с помощью имеющихся у языка дополнительных библиотек.
Результаты, на самом деле, были не очень удивительны — nodeJS уверенно идёт впереди планеты всей.
Очень порадовал PHP7 — очень хорошо чувствуется поднятие производительности в 7 версии по сравнению с 5.6. А вот почему результаты тестов генерации экспоненты с либами дали такой результат — пока не совсем понял.
Далее были протестированы фреймворки:
Тест очень просто и типичный для простых сайтов — достать информацию из базы, отправить на рендер в представление и вывести в буфер.
В данном случае берутся 3000 строк из Mysql из 10000 строк в базе и строится пагинация.
Вот тут SailsJS, если честно, удивил. Я ожидал, что всех своих конкурентов он резво уделает. А он ни то, что не уделал, но еще и проиграл Laravel'у.
Всё тестировалось без кэширования. При включенном кэшировании данные, конечно же, несколько другие, но картины не меняют.
Вывод
Буду продолжать тестировать языки и фреймворки на предмет скорости и удобства. На данном этапе ближе всего по удобству/скорости разработки и скорости работы приложения, организации кода для меня — Laravel.
Приветствуются замечания, комментарии и pull-реквесты в мой репозиторий.
Комментарии (36)
Leopotam
18.01.2016 21:44-3А так же поправить табличку потребления памяти у Laravel с учетом вебсервера (потому что nodejs — это полноценный сервер приложений, включая http-сервер).
DexterHD
18.01.2016 21:56php -S localhost:8000 (Хотя некорректно сравнивать потому что оно тока для разработки и работает медленно. Ни кто там за скоростью не гнался).
ckr
18.01.2016 21:59+2Всё тестировалось без кэширования. При включенном кэшировании данные, конечно же, несколько другие, но картины не меняют.
Вот это вы напрасно! Обычно, проводя нагрузочные тесты фреймворков для последующего сравнения результатов, подразумевают тестирование не способа генерации вывода данных (тут принципы почти одинаковы), а тестирование именно возможностей кэширования, что и куда кэшируется (тут отличительные принципы есть у каждого фреймворка).
Столбик Memory consumption во второй таблице немного непонятен.
В случае с Laravel и Yii, как я понимаю, показывает heap процесса после отработанной генерации одной странички.
А в случае с Rails и SailsJS Вы показываете heap всего сервера.
Что из этого следует? Если, например, запустить одновременно 10 потоков генерации странички Laravel, то объем общей занятой памяти на тестируемый момент будет 19.32 ? 10 = 193.2Mb. В этих же условиях, не факт что Rails и SailsJS принципиально увеличат объем занятой памяти.AxelPAL
18.01.2016 22:46-6Кэширование тоже бывает разным. Но интереса ради включу везде кэширование и проведу отдельный тест.
По поводу замера размера памяти — я, конечно же, понимаю, что так сравнивать не совсем корректно, но руби и нода стартуют сервером, в то время как встроенный сервер php — совсем не производительное решение.
Как вариант, конечно, перевести всё на один веб-сервер + подключить обработчики для языков. Хотя нода в любом случае будет запускать свой сервер, к которому нужно будет делать upstream.ckr
18.01.2016 23:07+1Кэширование тоже бывает разным.
Платформы тоже могут быть по-разному настроены. В NodeJS есть возможность загрузить какие-то данные в память один раз и пользоваться этими данными при выдаче каждой страницы. В php такое возможно лишь с использованием memcached и их аналогов. Существует также LRU-cache — это как кэш кэша. Значения наиболее популярных блоков памяти хранятся в одном массиве для наиболее быстрого доступа к ним.
Также, результаты могут отличаться как в лучшую, так и в худшую стороны, если php будет запускаться с какими-нибудь ioncube, zend optimizer, eAccelerator.
Для сравнительных тестов NodeJS, Ruby и PHP было бы справедливо суммировать затраченную память и CPU-time всех PHP-процессов и всех процессов вебсервера — Apache или Nginx или что-то еще (вы не указали).
Советую проводить нагрузочные тесты вот этой утилитой:
httpd.apache.org/docs/2.0/programs/ab.html
Source
19.01.2016 10:42+1в то время как встроенный сервер php — совсем не производительное решение
Вы так пишете как-будто Webrick (встроенный сервер для Ruby) — производительное решение. Добавьте в Gemfile строку
gem 'thin'
и посмотрите ещё раз (после bundle install).
А по теме статьи, Вы по сути выбираете из медленных технологий. Рассмотрите Elixir+Phoenix и Golang+Gin, если производительность без кеша имеет значение для вас :-)
DexterHD
18.01.2016 22:05Идиотский вопрос, но вас не смутило, что в PHP константа M_PI, это аналог функции pi() — и она вычисляет PI с заданой в php.ini точностью, ВЫЧИСЛЯЕТ. А в JS Math.PI — как я понял тупо предопределенная константа, те число зашитое в исходник? Если я не прав, расскажите, как изменить точность Math.PI или ткните меня в исходники бибилотеки Math для JS.
ckr
18.01.2016 22:11+5Загляните в исходники тестов, там имелся в виду тест простого алгоритма вычисления pi.
Конечно, M_PI и Math.PI это константы, и никто не собирался их рассчитывать в продакшене.
Суть в том, чтобы запустить один и тот же алгоритм на разных языках/платформах.
farcaller
18.01.2016 22:19+1В третьем тесте у питона 0.44s, а у ноды 0.68s. Я что-то не понимаю в выделении жирным?
AxelPAL
18.01.2016 22:40-3Да, немного ошибся. После обновления до 5 версии ноды стали такие результаты. Жирность не поменял. Спасибо за замечание.
Можете в коммитах посмотреть, какие показатели были на 0.12.7 версии ноды.
DexterHD
18.01.2016 22:53Забавно, но если просто обернуть PHP код из репозитория, для генерации Pi в класс и метод, то даже PHP 5.6 справляется за 4.8 секунд, смею предположить, что результат PHP 7 будет быстрее. Не знаю с чем это связано, но есть какой то подвох. Может связанный с объявлением глобальных переменных.
В то же время если обернуть JS, ни чего по таймингу не изменится.
ckr
18.01.2016 23:52+3Да, еще одно замечание автору. Не совсем по теме статьи, но я посчитал полезным и оставлю здесь.
В исполняемом скрипте SailsJSapp.js
Вы обернули код в конструкцию:
(function(){ })()
Данность явно указывает на то, что javascript вы знаете по front-end-у.
Такая конструкция уместна для изоляции переменных и прочего кода в браузерах, так как все скрипты работают с одной областью видимостиwindow
.
В Node.JS каждый модуль запускается в собственной области видимостиmodule
. Такая обертка у чисто серверного скрипта выглядит весьма странно.
Гораздо большего эффекта можно добиться, например, от strict-режима, чего в ваших скриптах не наблюдается:
'use strict';
AxelPAL
19.01.2016 07:34+1В случае с SailsJS использовал генератор проекта от самого Sails. Он и создал такой файл, его я не менял.
И вообще, если в фреймворке есть средства генерации кода — я его использовал. Это касается всех приведенных в статье фреймворков.ghaiklor
19.01.2016 11:36А лучше вы бы этот использовали — github.com/ghaiklor/generator-sails-rest-api
Тот генератор, который идет в поставке с Sails, убогий и ничего толкового не умеет.
hell0w0rd
19.01.2016 01:20+1Инструменты надо выбирать по задачам. Если у вас админка — в принципе наплевать, сколько будет генерироваться ответ с сервера, зато важна скорость разработки.
Если у вас реалтайм и вебсокеты, php в принципе рассматривать не стоит, не для этого он сделан.
А если уж тестируйте — делайте это правильно. У вас, судя по коду, куча копипасты с SO, или аналогов. Напишите везде один и тот же алгоритм.
Как вы тестировали затрачиваемую память — вообще не ясно.
Regis
19.01.2016 02:45+3Ересь какая-то. Сравнение теплого с мягким. В синтетических тестах. Баз каких-либо оптимизаций под указанную задачу в данном языке.
Bringoff
19.01.2016 08:57+2Интересно, и часто в проектах на PHP и RoR приходится экспоненту вычислять?
AxelPAL
19.01.2016 10:13-2Первый тест — вычислительная задача, чтобы количественно сравнить php/ruby/js+node.
Практического смысла, понятное дело, не имеет. Это показатель того, как языки (и нода) справляются с вычислениями.
Второй тест — более приближенный к жизни, хоть и показывающий простой и банальный use-case приложения.
poxu
19.01.2016 11:23-1Да в общем никогда. Как и использовать PHP и RoR, если нужна производительность.
VolCh
19.01.2016 11:35+3Фэйсбуку и Гитхабу производительность не нужна? :)
poxu
19.01.2016 14:36+4У Фейсбука столько легаси кода, что переписать его не получилось. Оказалось проще написать сначала транслятор в си, а потом свою виртуальную машину для php. Которая по производительности всё равно проиграет банальной джаве, не говоря уже о каком-нибудь Go. Если бы отыграть время назад, никто бы и не подумал делать Фейсбук на php. На одном только электричестве сэкономить миллионы можно.
У гитхаба запросы по производительности в сотни раз меньше, ему хватает того, что естьVolCh
19.01.2016 18:34Если бы отыграть время назад, никто бы и не подумал делать Фейсбук на php.
С одной стороны, история не знает сослагательного наклонения, а, с другой, не думаю, что Цукерберг бросился бы изучать Java, обладая сегодняшними знаниями о том как взлетела поделка на PHP. Там может задержка релизов на день была критична.poxu
19.01.2016 21:16Собственно так и есть. Делать не на том, чем владеешь, а на чём то другом обычно крайне неудобно.
komandakycto
19.01.2016 12:44Мне показалось, что поставленная задача (цель) не коррелирует с проведенными исследованиями
bromzh
19.01.2016 13:09+1Зачем, если уже есть www.techempower.com/benchmarks
Там хоть данные, близкие к практическим, т.е. работа с сетью, а не числодробилки и рекурсии, которые на практике оптимизируют по-всякому.
maxru
19.01.2016 16:44Хотелось бы хотя бы в общих чертах понять, какие насущные проблемы в web-программировании решает скорость вычисления числа PI.
DexterHD
Вывод в node.js вы конечно же в sync режиме использовали???
AxelPAL
Использовал конфиг SailsJs, шедший из коробки.