Какой язык программирования самый быстрый

от admin

Русские Блоги

Сравнение производительности Java, Python, Ruby, PHP, C и других языков

Функция кода:Петли шить строки и заменить подстроки

Аппаратная среда:Intel Core2 Duo [email protected] CPU; 2 GB RAM; OS Debian GNU/Linux 2.6.32 i686

Время выполнения кода

Таблица сравнения производительности кода

Использование памяти

Таблица сравнения памяти:

Тестовый исходный код:

C (source); Result: C gcc (Debian 4.4.4-1) 4.4.4

C++ (source) Result: C++ g++ (Debian 4.4.3-7) 4.4.3

Javascript (source); Results: Javascript (Spidermonkey — Mozilla) 1.8.0 pre-release 1 2007-10-03,
Javascript (V8 — Chrome)

Java (source) Results: Java (OpenJDK) "1.6.0 18",
Java (Sun) "1.6.0 16",
Java (gcj) (Debian 4.4.3-1) 4.4.3

Perl5 (source); Result: This is perl, v5.10.1

PHP (source); Result: PHP 5.3.1-5 with Suhosin-Patch (cgi-fcgi)

Python3 (source); Result: Python 3.1.3

Ruby (source); Result: ruby 1.8.7

Lua (source); Result: Lua 5.1.4

tcl (source); Result: tcl 8.4.19

вывод

По мере того, как версии языков обновляются, они постоянно оптимизируются. Чтобы эффективно использовать характеристики каждого языка, вам необходимо понимать его характер, и это нужно постоянно углублять.

Выбор языка — это как выбор любовника. В глазах любовника Сиши — лучший. То, что вам нравится, — лучший, так что не слишком верьте приведенным выше результатам.

Сравнение производительности ввода/вывода: C, C++, Rust, Golang, Java и Python

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

Сейчас существует большое количество языков программирования для создания бэкенд-сервисов. Это вызывает интерес в сравнении их производительности по различным критериям. К примеру, сервис Benchmarks Game сравнивает языки программирования на основе того, как они решают различные задачи. А TechEmpower измеряет производительность веб-фреймворков.

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

Это сподвигло меня выяснить настоящую стоимость затрат ресурсов, необходимых для “голого” ввода/вывода на различных платформах. Измерение прокси TCP, кажется, дается проще всего. Он включает только обработку входящих и исходящих соединений, а также передачу необработанных байтовых данных.

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

Можно сравнить следующие решения:

  • HAProxy в режиме TCP-прокси. Сравнение со старой реализацией на языке С: http://www.haproxy.org/.
  • draft-http-tunnel — простое решение на C++ с базовой функциональностью ( trantor ), запущенное в режиме TCP: https://github.com/cmello/draft-http-tunnel/.
  • http-tunnel — простой HTTP-туннель/TCP-прокси, написанный на Rust ( tokio ) и запущенный в режиме TCP: https://github.com/xnuter/http-tunnel/.
  • tcp-proxy — реализация на Golang: https://github.com/jpillora/go-tcp-proxy.
  • NetCrusher — реализация на Java (Java NI0). Тесты проводились на JDK11 с модулем G1: https://github.com/NetCrusherOrg/NetCrusher-java/.
  • pproxy — решение на Python, основанное на asyncio , запущенное в режиме TCP-прокси: https://pypi.org/project/pproxy/.

Все представленные выше решения используют неблокирующий ввод/вывод (non-blocking I/O). Если вам нужен действительно быстрый сервис с быстрым временем отклика и большой пропускной способностью, то можно воспользоваться этими прокси.

Примечание: я пытался подобрать лучшие реализации на Golang, Java и Python, однако допускаю, что могут найтись и другие решения на основе других материалов. В качестве бэкенд-сервера был выбран Nginx, который настроен на передачу 10 килобайт данных в режиме HTTP.

Результаты сравнения разделены на две группы:

  • Baseline, C, C++, Rust — высокопроизводительные языки.
  • Rust, Golang, Java, Python — языки с автоматическим управлением памятью.

Да, Rust есть в обоих списках.

Краткое описание методологии

  • Два ядра выделены для TCP-прокси (cpuset).
  • Еще два ядра выделены под бэкенд (Nginx).
  • Частота запросов начинается с 10 000, а затем плавно поднимается до 25 000 запросов в секунду (ЗВС).
  • Подключения будут переподключаться каждые 50 запросов (по 10 кб на запрос).
  • Все измерения запущены на одной виртуальной машине для исключения любых помех в соединении.
  • Виртуальная машина запущена в режиме вычислений (использует все доступные мощности процессора), чтобы избежать неточностей из-за работы фоновых программ.
  • Время отклика измеряется в микросекундах.

Для сравнения использовались следующие характеристики:

  • Перцентиль (от 50 до 99) — ключевая характеристика.
  • Погрешность (99.9 и 99.99) критична для компонентов крупных распределенных систем.
  • Максимальное время отклика (никогда не следует пренебрегать такими данными).
  • Среднее усеченное значение — значение без учета 0,1% лучших или худших исходов вычисления для вычисления среднего значения (без погрешности).
  • Стандартное отклонение от нормы — для расчета стабильности времени отклика.

По ссылке можно почитать о методологии и о том, почему были выбраны именно эти характеристики. Для сбора данных использовалась программа perf-gauge.

А теперь перейдем к результатам.

Сравнение высокопроизводительных языков: C, C++, Rust

Часто говорят, что Rust стоит наравне с C/C++ с точки зрения производительности. Рассмотрим, насколько именно “наравне” они находятся в плане обработки ввода/вывода. Ниже показаны четыре графика в порядке языков: точка отсчета, C, C++ и Rust.

На таблице ниже видно, сколько миллисекунд добавляется поверх основного бэкенд-запроса для каждой характеристики. Эти числа выражают средние значения интервала между максимальной частотой запросов (наращивание частоты в измерение не включено):

А вот как это выглядит в сравнении (потери пропускной способности в процентах от базовой точки отсчета):

Интересно, что прокси, написанный на C++, немного быстрее, чем HAProxy и Rust на уровне 99,9, однако медленнее на уровне 99,99 и выше. Стоит отметить, что, вероятно, это особенность простой реализации прокси, которая написана на колбэках, а не на обработке событий. Кроме того, были произведены замеры потребления памяти и мощности процессора. С ними можно ознакомиться по ссылке.

В заключение хочется сказать, что все три TCP-прокси, написанные на C, C++ и Rust, показали схожую производительность, а также плавную и стабильную работу.

Сравнение языков с автоматическим управлением памяти: Rust, Golang, Java, Python

А теперь приступим к сравнению этой выборки языков. К сожалению, решения на Java и Python не смогли справиться с 25 000 запросов в секунду всего на двух ядрах, поэтому Java была измерена на 15 000 ЗВС, а Python — на 10 000 ЗВС. Картинка ниже отражает статистику языков Rust, Golang, Java и Python.

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

Читать:
Recent files keys что это

Golang не отстает на уровнях 50 и 90, однако разница в значениях сильно растет на более высоком перцентиле, что отражается в значения отклонения от нормы. Но взгляните на значения на Java!

Стоит взглянуть на перцентили с отклонениями (99,9 и 99,99). Легко заметить, что разница с Rust просто огромна.

А вот как это выглядит в сравнении (процент от базовых значений Nginx):

В заключение можно сказать, что Rust показывает намного меньшее время отклика по сравнению с Golang, Python и, в особенности, Java. Golang соответствует производительности Rust только на уровне 50 и 90.

Максимальная пропускная способность

Есть еще один интересный вопрос: какое максимальное количество ЗВС может обработать прокси на каждом языке? Как и всегда, полные расчеты можно прочитать по ссылке, а мы перейдем к краткой выжимке.

Nginx способен обработать примерно 60 000 ЗВС. Если между клиентом и бэкендом добавить TCP-прокси, пропускная способность уменьшится. На графике видно, что C, C++, Rust и Golang развивают только 70–80% от пропускной способности Nginx, а Java и Python и того меньше.

  • Синяя линия означает время отклика (левая шкала по оси Y) — чем меньше, тем лучше.
  • Серые столбцы обозначают пропускную способность (правая шкала по оси Y) — чем выше, тем лучше.

Заключение

Эти измерения не являются комплексными и полноценными. Их цель — сравнение “голого” ввода/вывода на различных языках.

На основе этих тестов напрашивается вывод, что Rust может стать лучшей альтернативной по сравнению с Golang, Java или Python, если для вас важна стабильная производительность. Именно поэтому перед тем, как начинать писать программу на C или C++, следует подумать о реализации на Rust. Помимо высокой производительности на уровне C/C++ и того, что он подталкивает к созданию полного скелета программы еще до начала разработки, будут доступны и другие преимущества:

«Дело было вечером, делать было нечего» или краткая история о сравнении производительности языков программирования

«Бенч» дело такое. После нескольких дней бездействия начинается ломка, хочется занять себя чем-нибудь. Иногда я отвлекался на pet-проекты, иногда на чтение литературы. Сейчас же я расскажу о том что случилось во время последнего «режима ожидания».

Меня многие годы волновала производительность ЯП (в основном интересовал PHP). Список ниже содержал некоторые мои убеждения, до недавнего времени:

PHP один из самых медленных языков программирования

Python быстрее PHP

Ruby быстрее PHP

C/C++ намного быстрее Python и PHP вместе взятых

Assembler на порядок быстрее C/C++

Первым делом нужно было определиться какой тест взять за основу. А давайте попробуем написать программу нахождения простых чисел (я в курсе что есть много алгоритмов нахождения простых чисел, неплохая статья на данную тему).

За основу был взят следующий код (примитивный перебор, который даже не прекращается, если уже знает что число не простое):

А дальше все как в тумане: Python, C/C++, Pascal, Go и тд. Все исходники можно глянуть здесь. Все тесты я делал в докере, чтобы не засорять комп.

Потом я наткнулся на книги Андрея Викторовича Столярова, и все завертелось с еще большей силой. Assembler я не трогал со времен универа, но после прочтения книги очень захотелось что-то написать. Могу сразу сказать, что тест для Assembler/NASM я писал больше недели, хотя на любой ЯП из тех что представлены в репозитории уходило не больше часа.

Вот в принципе и результат моей работы:

После того как начали появляться первые результаты, я удивлялся все сильнее и сильнее:

оказывается PHP быстрее Python и Ruby

PHP вообще один из самых быстрых интерпретируемых языков

Python 3 медленнее Python 2

разница в работе программы написанной на С/C++ и Assembler/NASM в районе 15%

после Rust пришлось добавить тесты с флагом на компиляцию с оптимизацией

очень удивил результат теста Node.js/Javascript (разработчики V8 — красавцы)

На данный момент я планирую постепенно добавлять новые тесты (когда позволяет время и настроение).

Цель данной статьи стоит не в том, чтобы показать какой ЯП самый быстрый, а в том что мы можем ошибаться в своих убеждениях, и что не стоит верить всем байкам в курилке (многие из моих заблуждений именно оттуда, кто-то где-то слышал что X быстрее Y).

PPS. Добавил Ruby 3, что-то не сильно помогло.

PPPS. Изменил метод подсчета времени выполнения, увеличил порядковый номер простого числа (с 5000 на 7000).

PPPPS. Добавил Haskell.

PPPPPS. Добавил Lua (LuaJIT) и Python 2/3 (PyPy).

Сравнение скорости языков. Неужели Pascal самый быстрый?

Всем привет! Решая очередную задачу из ЕГЭ наткнулся на задание:

Найдите все натуральные числа, принадлежащие отрезку [106 000 000; 107 000 000], у которых ровно три различных чётных делителя. В ответе перечислите найденные числа в порядке возрастания.

Написал решение на Python:

Работает достаточно медленно, как и ожидалось, и у меня возникла замечательная идея написать на более быстром языке и выбрал С++ (Visual Studio) Написал код:

Отлично, работает быстрее, однако решил проверить задание из примера и удивился, что код на Pascal`е, по сути идентичный, работает в 2 раза быстрее:

Получается, что Pascal самый быстрый язык программирования и всё это время нам врали?

Harry's user avatar

Мне стало любопытно сравнить С++ и Pascal.

Платформа Linux Ubuntu, 64-bit. Компиляторы:

Чуда не произошло: С++ компилятор в данном конкретном случае выдает в шесть раз более быстрый код.

P.S. Разница велика. Я проверил различные оптимизации доступные на платформах. GCC без оптимизаций замедляется в четыре раза, FPC во всех вариантах -Cf. -Op. показывает одно время — разница не более десяти процентов.

P.P.S. Я буду благодарен если вы укажите мне мои промахи. Возможно, я не умею использовать FPC.

Stanislav Volodarskiy's user avatar

Паскаль оценивает предел цикла внутреннего цикла for (где используется медленная вещественная операция sqrt ) только один раз перед каждым запуском этого цикла.

Как дело обстоит с С++ — вероятно, зависит от оптимизатора.

В целом же обычно компиляторы C++ выдают код лучшего качества.

Есть ещё важный вопрос — как Вы измеряли? Какова точность?

Сделал тест. На 3.1 ГГц процессоре поколения Haswell (Xeon 1220v3, примерно как i5 4440) Delphi выдаёт 1.4 с.

C++ VS 2017 (стоит максимальная оптимизация -O2, как -O3 включить в среде — я не знаю) тратит 5.7 с. Если заменить предполагаемую зловредную строку на одноразовое вычисление

то время становится 1.2 с, что вполне согласуется с обычным соотношением скорости генерируемого кода на простых примерах (при возможности векторизации и т.п. компиляторы C++ дадут жару).

Судя по тесту Stanislav Volodarskiy, gcc c -O3 догадывается, как лучше оптимизировать.

Похожие статьи