Когда JavaScript БЫСТРЕЕ, чем язык C

preview_player
Показать описание
Почему язык программирования JavaScript был спроектирован так, чтобы быть производительнее, чем C и пример программы, которая на JavaScript выполняется быстрее, чем на C.
0:00 Введение
0:17 Как работают языки программирования
0:42 Производительность и способы оптимизации кода
3:25 Компиляция и интерпретация
5:30 Оптимизации в разных видах компиляторов
6:55 Пример кода, работающего быстрее на JS, чем на C
8:13 Выводы

ССЫЛКИ
Рекомендации по теме
Комментарии
Автор

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

aocore
Автор

Извините, вы ошиблись!)
Продвигаю грамотный С/С++ в массы.
1. Делаем inline функцию g()
2. Делаем константным указатель (*const fun_ptr)
3. Навешиваем перед g() и указателем volatile, чтобы избежать компайл-тайм подсчета
Получаем 13 строчек ассемблерного выхлопа c -O3 вместо 26 из вашего примера
Время выполнения на моем пк(Windows 10, Ryzen 3600x, 16GB RAM) снижается с 45 секунд до 10(без инлайна будет 10.5)
Поясняю: константность указателя дает компилятору уверенность в том, что нет смысла разыменовывать указатель, можно делать вызов напрямую, а тут у нас еще и инлайн - можно вообще вставить все в main( так и происходит)
Получаем обход разыменования и call инструкции, за счет чего выигрываем в 5 раз
Считаю эти апгрейды абсолютно легальными - ведь JS делает все оптимизации за разработчика, а в Си нужно дружить с компилятором
P.S если будете проверять мои слова - компилируйте как C++, потому что gcc выносит все в компайл тайм и просто возвращает посчитанное число, а с g++ у меня как-раз вышло 13 строчек
как-то так(когда вставляю ссылку в комментарий - он удаляется):
volatile inline unsigned int g(void) { return 1; }

volatile unsigned int (*const fun_ptr )(void) = &g;

int main(void) {
unsigned long long i, j, ret = 0;
for (i = 0; i < 40U; i++)
for (j = 0; j < 1'000'000'000U; j++)
ret += (*fun_ptr)();
return ret;
}

maksimsivyy
Автор

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

alexanderchesnokov
Автор

"Давайте я напишу страшно неоптимальную программу на Си и сравню с более-менее приличной на JS. Ого! На Си работает медленнее! Ура! Мы постарались обдурить компилятор, и у нас получилось"

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

DmitriyMerkushov
Автор

Очень понравились виды Амстердама. Спасибо!
Делайте так ещё ;)

Eustrop
Автор

Вы еще зарекнитесь, что ассемблер медленнее C# :D

freeshooter
Автор

Алексей. Попробуйте компрессор на звук наложить во время монтажа. Например в Adobe Audition. Это не очень сложно - звук очень прыгает по громкости. Перегрузка по частотам присутствует.

dark.lizzard
Автор

Подача стала динамичнее, спасибо за видео

neurowave
Автор

8:06 *Пример кода да и вообще*
Это видео, прекрасный пример того, что бывает, когда человек который не понимает что он делает считает о себе иначе.
А ситуация, которая привела к нужному ему результату не имеет ничего общего с тем, о чем он рассказывает.
Ну знаете, это как тесты на IQ, когда человек который оказывается умнее того, который составил тест, получит в этом тесте наименьшую оценку в силу того, что его ответы неверны с позиции автора теста.

То есть вопрос тут не в том, что С код может быть лучше или быстрее или наоборот, а в том, что автор измеряет что угодно, но только не то о чем пытается рассказать. И делает это потому, что в принципе не представляет как сейчас работает TurboFan (оптимизирующий компилятор в JS)

*Сначала о JS коде автора*
Никакого Inline кода JS функции в примере автора нет. Он бы это и сам увидел если бы умел пользоваться такими конструкциями как allow-native-syntax print-code print-bytecode print-opt-code и так далее.

Если бы автор видео знал о том, что даже в Google Chrome он мог бы воспользоваться этими конструкциями и получить как байткод так и машинный код генерируемый рантаймом то знал бы, что инлайн его функции произошел бы в лучшем случае на третий вызов родительского цикла. Вне зависимости от того как много итераций он в него влепил. Современный JIT не может оптимизировать тот цикл который сейчас выполняется и это понятно почему.
Что же тогда произошло?

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

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

Совершенно естественно, что между просто вызовом функции, даже в случае машинного call это будет много медленее чем подстановка вместо него константы 1.

Но и это еще не все. Если бы автор знал что он делает, то он бы понял, что его JS код мог бы быть почти в 100 раз быстрее. Если бы его циклы были в пределах макисмального знакового числа помещающегося в 31 бит (именно 31 а не 32). Тогда бы автор вообще бы получил космическую скосрость выполнения JS кода, которая бы возможно заставила бы его задуматься - а не ошибся ли я.
Но он этого не сделал и получил ситуацию, когда его код в процессе выполнения был вынужден изменяться. Когда в начале рантейм пытался применять самую простую арифметику с цифрами которые поещались в регистры процессора (я ихсожу из того что код выполнялся на 64 битной ситеме) после переполнения же, код был вынужден перейти к работе с числами с плавающей запятой, несмотря на то, что числа все равно были целыми.

Я не помню как сейчас обстоят дела в C, но раньше, C вел себя оптимальнее в этом случае. То есть не переходил на работу с математикой в стандарте IEEE-754.

*Вместо ИГОГО*
Автор видео, тестировал что угодно но только не то о чем пытался рассказать.
Произошло это потому, что автор видео понятия не имеет о том, как в дейтвительности сейчас работает код в JavaScript в случае работы оптимизирующего компилятора.
Добавьте к этому еще и то, что автор видео не дал себе труда разобраться хотя бы поверхностно в теме то есть научиться получать от V8 байт код и машинный для случаев его оптимизации или нет.

Да черт с ним код. В V8 он мог получить подробный лог сообщений, как когда и при каких условиях оптимизировался конкретно его код строка за строкой. И, что самое главное, деоптимизировался. Потому что в современном V8, самая страшная проблема производительности не то, что код остался не оптимизированным, а то, что код все время то оптимизируется то деоптимизируется.
И по хорошему - автору должно быть стыдно как программисту. С другой стороны может он деньги зарабатывает.

*Может ли быть код на JS быстрее кода на C*
Правильный ответ - да может и часто может быть быстрее во много раз. Почему? Потому что производтельность кода на C зависит только от квалификации программиста (за вычетом ошибок компилятора), но производетльность кода на JS зависит от оптимизирующего компилятора который умеет делать фантастические вещи, и от задачи с которой он компилятор умеет справляться. Как итог, в сухом остатке типичный программист на С сейчас с легкостью. напишет код который будет медленнее аналогичного кода на JS. Особенно в случаях многократных повторений. И хорошим примером тому может быть эволюция того как писался SpiderMokey.

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

*Как шуточный пример*
Если задать задачу плохому программисту на C и отвратительному программисту на JS найти все числа которые является четными,
как первый так и второй может предложить решение где четность определяется остатком от деления на 2. При этом оптимизирующий компилятор JS этот код сразу приведет к состоянию test al, 1 а вот код на C может получить много вариаций. Потому что страшна не граната, а обезьяна с гранатой, которая не знает как ей пользоваться.

demimurych
Автор

мне кажется js в данном случае использует константный референс на эту функцию, тогда можно легко сделать тоже самое в C и получить время исполнения 0.002 секунды)

ackz
Автор

Если тестировать программы автора, то скорость примерно одинакова по 45 сек на i7-8700K. Но если в вызывать саму функцию g(), то при флагах оптимизации o2 и о3 компилятор считает результат вызова g() на этапе компиляции и такая программа работает мгновенно. Но при флаге o1 программа начинает вызывать функцию g() в рантайме. и тогда сишная программа работает всего 8-9 сек, т.е.примерно в 5-5.5 раз быстрее. Т.ч. автор ролика не прав утверждая, что даже в простых вещах js быстрее C.

aleksandrshevchenko
Автор

Прикольно!)
Можно ещё припаять время разработки, тогда JavaScript будет быстрее в гораздо большем количестве случаев)

victormakovchik
Автор

Ну так можно сказать, что JS быстрее ассемблера (Debian под VMWare, виртуалка, конечно, накладывает свой отпечаток на результаты, но несколько прогонов показали примерно те же значения).
js: 0m39.285 s
c: 0m57.602 s
asm: 0m57.570 s - показатели на уровне С, разницу в 0.1 можно считать погрешностью, что и не удивительно, ведь машинный код, по сути, получается тот же (смотрел дизассемблером).

Только такие синтетические тесты к реальности ни какого отношения не имеют, а нужны только для кликбейтных заголовков.
p.s. Я, конечно, не спец в asm'е (скорее, даже джун), но задача была не оптимизировать, а приблизить решение к предоставленному коду на С. Дизассемблирование исполняемого С файла показало, что, практически, это удалось.

global _start
section .text
g: mov eax, 1
ret
_start:
xor ebx, ebx
mov edi, g
mov ecx, 40
.lp1: mov edx,
.lp2: call edi
add ebx, eax
dec edx
jne .lp2
dec ecx
jne .lp1
mov eax, 1
int 80h

PTolkachev
Автор

Если в си сделать конст указатель на функцию то программа будет работать 0.002 сек(погрешность time, как вам такая оптимизация статической компиляции?). А если в js заменит все конст на let, то время не изменится так что за это лайк js. У меня было время си: 51s, js: 41s на изначальных

letsadoptloli
Автор

"Объектный" код, подаваемый на выполнение процессору, режет ухо. По традиции этот код называется "машинным". А "объектным", опять же по традиции, называется код, выдаваемый классическим компилятором после компиляции отдельного файла (те самые .OBJ-файлы).

lolphdundgren
Автор

я посмотрел только минуту а уже возникло желание закинуться спидами, просто чтобы успевать... так и хочется сказать чувааааак помедленнее я ж записываю
ну и хронометраж 11 минут можно запросто растянуть на 15 никто ж не умрёт от этого... а так да все ролики что смотрел все клёвые, спасибо тебе лёха.

FCProF
Автор

Все что может быть написано на JavaSript - будет написано на JavaScript (c)

AlexFour
Автор

Так я не понял, какая у C "позорная тайна", вынесенная на превью? Ой, простите, забыл, что "кликбейт" - наше всё.

PTolkachev
Автор

Классный формат подачи материала!!) Очень интересно)

zmqmvhb
Автор

JavaScript Быстрее чем C? Да, но всем всё равно

jevudi