habrahabr

Сравнение производительности: JavaScript vs компилируемые языки

  • пятница, 14 июня 2019 г. в 00:17:27
https://habr.com/ru/post/455876/
  • Высокая производительность
  • JavaScript
  • Программирование
  • C++
  • C#


Периодически, беседуя при найме с кандидатами, а также коллегами, слышу высказывания плохого мнения о JavaScript от «бывалых» программистов, привыкших писать на C++, Java, C#, Delphi. В дискуссиях на тему «JS — это вообще не язык» я не участвую, но когда заходит речь про эффективность, производительность, скорость разработки — я люблю послушать и высказаться.
Я часто привожу такой тезис — несмотря на все недостатки JavaScript, сейчас это уже довольно мощный и многоцелевой инструмент, одним из важнейший достоинств которого для бизнеса является существенно более высокая скорость разработки. То есть написать код и решить задачу на JS часто бывает намного быстрее, чем на «нормальном» языке и результат получается вполне удовлетворительным. Уменьшить количество багов помогает надстройка над JS в виде TypeScript. В качестве контр-аргумента мне часто приводят низкую производительность кода на JavaScript. Я не являюсь поклонником JS, но мне стало интересно — насколько медленным является современный JS в сравнении с «взрослыми», компилируемыми языками.

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

Я решил взять какой-нибудь простой алгоритм с целочисленной арифметикой и реализовать его на нескольких языках максимально идентично. Мое исследование не претендует на серьезный бенчмарк и тем более я никого не уговариваю срочно переходить на JS или C# или какой-либо другой язык.

Я выбрал задачу генерирования последовательности простых чисел. Вот так выглядит реализация на С:

#include "stdafx.h"
#include <cstdio>
#include <ctime>

int main()
{
	int Max = 500000;
	int nums[100000]; //100 тыщ
	nums[0] = 2;
	int j = 1;

	clock_t t;
	t = clock();

	for (int cur = 3; cur < Max; cur += 2) {
		int half = cur / 2;
		bool isPrime = true;
		for (int i = 0; nums[i] <= half; i++) {
			if ((cur % nums[i]) == 0) {
				isPrime = false;
				break;
			}
		}

		if (isPrime) {
			nums[j] = cur;
			j++;
		}
	}

	t = clock() - t;
	printf("Time to gen %d primes (up to 500 000) : %f seconds.\n", j, ((double)t) / CLOCKS_PER_SEC);

    return 0;
}

Также я реализовал этот алгоритм на C#, Delphi и JavaScript полностью идентично, насколько это возможно. Я использую Windows 10, поэтому использовались следующие инструменты:
для С — компилятор из Visual Studio 2019 Community
для C# — .NET Core SDK 2.2.300
для Delphi — Delphi XE Win32 (2010 года)
для JS — Node.js v. 10.16
Выполнение вычислений из приведенной выше программки на С заняло на моем компьютере 1,2 секунды. Это лучший результат из 4-х языков, которые я сравнивал.
Как вы думаете, в каком порядке выстроились остальные языки по увеличению времени работы и уменьшению производительности соответственно? Какой язык оказался самым медленным? Насколько сильный разрыв между между результатами других языков?

Через несколько дней я дополню статью результатами, а пока предлагаю проголосовать и написать свое мнение в комментариях.

P.S. (на следующий день)
Уже накопился достаточный результат голосования. Спасибо всем, кто проголосовал.
Спасибо тем, кто указал на недостатки данной задачи для применения ее в качестве бенчмарка.
Те кто спрашивал про «сколько раз запускались тесты» — отвечаю «не менее 10 раз» и на расстановку мест это никак не повлияло.

Теперь про результаты.
1. Компилятор Delphi хоть и достаточно старый и генерирует 32-битный код, тем не менее этот код нативный и для данной задачи достаточно оптимальный. Отставание от самого современного компилятора С/С++ составило менее 10%. Результат программы на Delphi — 1,34 секунды (против 1,2 секунды у C/C++).
2. Node.js, начиная с версии 8 довольно заметно подтянулся в скорости, это замечали многие на многих задачах. В данной задаче результат JS — 2,15 секунды. То есть данный алгоритм, будучи реализованным на JS уступает реализации на C/C++ менее чем в 2 раза.
3. Результат C# — (обновлено) 1,9 секунды при использовании списка и массива. Предыдущая моя информация тут была недостоверна, так как я забыл удостовериться, чтобы запускалась версия, собранная в релиз (запускал из командной строки). Я действительно знаком с C# на уровне «Hello World».

30,6% проголосовавших за вариант «C, Delphi, C#, JavaScript — Delphi уделывает C# и JS» — оказались правы. Другое дело, что разница результатов C# и JavaScript очень невелика.

Какими доводами можно объяснить 15% голосов за «C, C#, JavaScript, Delphi» и почти 13% за «C, Java Script, C#, Delphi» — у меня нет идей. То есть, по моему мнению, 28% проголосовало не представляя себе, что такое Delphi.

24% проголосовавших за вариант «C, C#, Delphi, JavaScript» видимо выражали надежду на то, что современные компилятор и среда исполнения C#, несмотря на свои архитектурные особенности, все таки одолеют устаревший компилятор Delphi. Были комментарии о том, как крута Java сейчас. Но тем не менее компиляторы, генерирующие нативный процессорный код, все же немного эффективнее.

Вместо вывода
В данном эксперименте меня удивили 3 пункта:
1. Довольно хороший результат JavaScript (исправлено).
2. Неадекватно-агрессивная и даже болезненная (как я считаю) реакция очень многих читателей на простое предложение порассуждать о производительности современных языков программирования. Я не знаю в чем причина — в ненависти к JavaScript или ко мне лично, но хотелось бы понимать эту причину (в комментариях мне уже разъяснили — написание Java Script — с пробелом — вызывает приступы ярости).
3. Некоторые из комментировавших потрудились написать комментарий и дать ссылки на другие бенчмарки, но при этом затруднились сформулировать собственное мнение по заданному вопросу хотя бы на основе разглядывания картинок по ссылкам, которые они привели. Если уж вы следите за бенчмарками и у вас есть мнение о языках, то почему не высказать его? А так получается, что «я знаю там есть ответ, но какой там ответ — я не знаю». Мне кажется так проявляется эффект постоянного наличия поисковика под рукой — можно не держать в голове знания и даже не иметь собственного мнения, ведь их всегда можно «погуглить».

Спасибо всем, кто принял участие в опросе!