TL;DR: в нижней части этой статьи приведены сравнения производительности и нагрузки. Я также предоставил общедоступный репозиторий с примерами кода, которые я реализовал, где вы можете открывать новые запросы на вытягивание, чтобы поддерживать его расширение с другими языками.

Многие (глупые?) люди пишут сообщения в Интернете, пытаясь «заставить» новых разработчиков изучать ИХ предпочитаемый язык программирования без какой-либо реальной причины или факта. Поэтому я решил написать пост об основных отличиях и сравнить их с производительностью и нагрузочными тестами, выложив в общий репозиторий код и результаты.

Сценарные (интерпретируемые) языки программирования

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

Преимущества языков сценариев:

  • Простота использования. Языки сценариев, как правило, имеют более высокий уровень абстракции, более простой синтаксис и семантику, что упрощает их изучение и использование.
  • Быстрая разработка: так как нет необходимости в этапе компиляции, их разработка часто может быть быстрее, а программы можно сразу тестировать и отлаживать.
  • Гибкость. Учитывая их интерпретируемый характер, они более гибкие и часто могут быть встроены в другое программное обеспечение.

Однако из-за своей интерпретируемой природы они могут быть медленнее, чем компилируемые языки, и их производительность может быть недостаточной для приложений с интенсивными вычислениями.

Примеры языков сценариев, среди прочего:

  • JavaScript
  • Перл
  • PHP
  • Рубин

Компилируемые языки программирования

Компилируемые языки (ошибочно называемые «языками программирования», поскольку и сценарии, и компилируемые языки являются языками программирования) — это языки, в которых исходный код транслируется в машинный код (или байт-код). компилятором перед его запуском. Аппаратное обеспечение компьютера может выполнять скомпилированный код напрямую, что делает его более быстрым и эффективным, чем интерпретируемый код.

Преимущества компилируемых языков:

  • Производительность. Скомпилированный код работает быстрее и эффективнее, поскольку компилятор оптимизирует его для целевого оборудования.
  • Безопасность. Исходный код на скомпилированном языке не виден конечному пользователю, что обеспечивает дополнительный уровень безопасности и защиты.
  • Управление ресурсами. Они часто обеспечивают больший контроль над системными ресурсами, такими как память.

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

Примеры компилируемых языков, среди прочего:

  • C (и их варианты C++ или C# или Objective C)
  • Go (также известный как GoLang)
  • Ржавчина
  • Быстрый

Гибридные языки программирования

Есть несколько случаев, когда некоторые гибридные языки программирования считаются обоими типами (интерпретируемыми и компилируемыми языками) одновременно, в то время как на самом деле они не являются ни тем, ни другим. Тем не менее, они категоризированы «в удобном виде», учитывая характер их реализации в реальных проектах.

Два примера этого — Python и Java. Оба языка компилируют свой программный код в байтовый код, а затем виртуальная машина выполняет полученный байтовый код.

Почему Python считается «языком сценариев»:

Python обычно относят к языку сценариев по нескольким причинам:

  • Модель выполнения. Стандартная реализация Python, CPython, представляет собой интерпретатор, который компилирует код Python в байт-код, а затем интерпретирует этот байт-код. Хотя Java также компилируется в байт-код, как вы заметили, принципиальное отличие состоит в том, что затем байт-код обычно JIT-компилируется в машинный код во время выполнения. Таким образом, хотя оба языка используют байт-код, у них разные модели выполнения.
  • Случай использования: Python часто используется в ситуациях, типичных для языков сценариев, таких как анализ данных, задачи автоматизации, прототипирование и веб-скрипты. Термин «язык сценариев» обычно больше относится к варианту использования языка, чем к его техническим характеристикам.
  • Простота использования и гибкость. Python обладает многими характеристиками языков сценариев, такими как динамическая типизация, простота использования и возможность выполнять код без отдельного этапа компиляции. Это больше о быстром цикле записи-запуска-отладки, который предлагают языки сценариев.
  • Исторические причины: Python изначально разрабатывался как язык сценариев для ОС Amoeba и с тех пор сохраняет это название.

Почему Java считается «компилируемым языком»:

Хотя Java можно назвать компилируемым языком, он работает немного иначе:

  • Для кода Java требуется компилятор Java: код Java пишется на языке высокого уровня, а затем компилируется компилятором Java (javac) в независимый от платформы байт-код (файл .class). Этот байт-код не может выполняться напрямую аппаратным обеспечением машины, но предназначен для интерпретации виртуальной машиной Java (JVM), программным интерпретатором.
  • Компилированному коду Java требуется механизм выполнения: во время выполнения этот байт-код либо интерпретируется, либо компилируется в машинный код JIT-компилятором JVM, что делает Java гибридом компилируемого и интерпретируемого кода. языки.
  • По сути, Java компилируется дважды: сначала в байтовый код, а затем в машинный код во время выполнения. Этот двухэтапный процесс позволяет Java быть независимым от платформы (благодаря байт-коду), в то же время используя некоторые преимущества скорости компилируемых языков (благодаря JIT-компилятору).
  • Java не приводит к машинному коду: поэтому, хотя Java включает в себя этап компиляции, он не компилируется непосредственно в машинный код, как это делают традиционные компилируемые языки, такие как C или C++, и не интерпретируется построчно. -line во время выполнения, как это делают традиционные языки сценариев, такие как Python или JavaScript. Вместо этого он попадает в золотую середину между ними.

Когда использовать каждый

[изображение]

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

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

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

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

Сравнение производительности

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

Мои тесты производительности основаны на очень простом ответе HTTP JSON, когда система не выполняет никаких операций или после запуска набора математических, текстовых, циклических и условных действий.

Тест №1: необработанное «Hello World»:

{
  "server": "<engine name>",
  "hello": "world"
}
  • JavaScript (NodeJS): 0,026 секунды
  • Питон: 0,035 секунды
  • PHP: 0,039 секунды
  • TypeScript (Deno): 0,151 секунды
  • GoLang: 0,054 секунды

Тест №2: очень долгая итерация цикла:

{
  "server": "<engine name>",
  "hello": "world",
  "loop": 1_000_000_000,
  "elapsedTime": <milliseconds>
}
  • JavaScript (NodeJS): 0,547 секунды
  • Python: 11,242 секунды
  • PHP: 2,554 секунды
  • TypeScript (Deno): 3,844 секунды
  • GoLang: [не проверено/еще не реализовано]

Тест №3: математика, текст, цикл и условные операции

{
  "benchmark": {
    "math": "<processing time in seconds>",
    "string": "<processing time in seconds>",
    "loops": "<processing time in seconds>",
    "ifelse": "<processing time in seconds>",
    "total": "<processing time in seconds>"
  },
  "sysinfo": {
    "time": "<current date time>",
    "<engine version>": "<engine version>",
    "platform": "<docker linux platform>",
    "server_name": "<docker container name>"
  },
  "version": "<benchmark tests version>"
}
  • JavaScript (NodeJS): 0,183 секунды
  • Python: 0,279 секунды
  • PHP: 0,136 секунды
  • TypeScript (Deno): 1,150 секунды
  • GoLang: [не проверено/еще не реализовано]

Сравнение стресс-тестов (или нагрузочных тестов)

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

Мои стресс-тесты основаны на тех же операциях, которые описаны в разделе «Тесты производительности», но в этом случае я выполнил 12 потоков и 400 одновременных подключений, используя специальные инструменты для стресс-тестов:

Тест №1: необработанное «Hello World»:

{
  "server": "<engine name>",
  "hello": "world"
}
  • JavaScript (NodeJS): 655_012 запросов (21_808,13 запросов в секунду)
  • Python: 2_477 запросов (82,35 запросов в секунду)
  • PHP: 4_788 запросов (159,27 запросов в секунду)
  • TypeScript (Deno): 293_889 запросов (9_770,41 запросов в секунду)
  • GoLang: 1_213_271 запросов (40_361,98 запросов в секунду)

Тест №2: очень долгая итерация цикла:

{
  "server": "<engine name>",
  "hello": "world",
  "loop": 1_000_000_000,
  "elapsedTime": <milliseconds>
}
  • JavaScript (NodeJS): 91 запрос (3,03 запроса в секунду)
  • Python: 2 запроса (0,07 запроса в секунду)
  • PHP: 11 запросов (0,37 запросов в секунду)
  • TypeScript (Deno): 10 запросов (0,33 запроса в секунду)
  • GoLang: [не проверено/еще не реализовано]

Тест №3: математика, текст, цикл и условные операции

{
  "benchmark": {
    "math": "<processing time in seconds>",
    "string": "<processing time in seconds>",
    "loops": "<processing time in seconds>",
    "ifelse": "<processing time in seconds>",
    "total": "<processing time in seconds>"
  },
  "sysinfo": {
    "time": "<current date time>",
    "<engine version>": "<engine version>",
    "platform": "<docker linux platform>",
    "server_name": "<docker container name>"
  },
  "version": "<benchmark tests version>"
}
  • JavaScript (NodeJS): 326 запросов (10,84 запроса в секунду)
  • Python: 140 запросов (4,65 запроса в секунду)
  • PHP: 298 запросов (9,91 запросов в секунду)
  • TypeScript (Deno): 0 запросов (0,00 запросов в секунду)
  • GoLang: [не проверено/еще не реализовано]

Обзор показателей:

Метрики показывают, что асинхронные языки сценариев (такие как JavaScript) намного быстрее и устойчивее, чем синхронные языки программирования (такие как PHP), способны обеспечивать более быстрые ответы и поддерживать более высокие нагрузки (такие как часы пик и DDoS-атаки).

Те же показатели показывают, что не все языки программирования могут обрабатывать одинаковый объем запросов. Обратите внимание, что PHP значительно снижает объем запросов по сравнению с JavaScript; однако Python не может обслужить даже один ответ.

Тем не менее, скомпилированные языки (например, GoLang) могут обрабатывать и обслуживать в два раза больше запросов, чем скриптовые (интерпретируемые) языки программирования (например, JavaScript).

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

Заключение

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

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

Ресурсы

Репозиторий исходного кода:

  • Общедоступный и открытый репозиторий GitHub (вклады принимаются): https://github.com/DavidGarciaCat/performance-and-stress-tests
  • В этом репозитории ☝️ вы можете найти образцы кода и метрики, собранные для написания этой статьи на Medium.

Официальные (или соответствующие) сайты:

Изображений