Как стать автором
Обновить

Комментарии 65

Не очень понимаю чему тут удивляться. Видя разницу между TypeScript и JavaScript, сразу приходит на ум JIT. Asm.js тоже JavaScript, только сделан что-бы лучше джитился.


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

Ну какой рантайм в числодробилках? После JIT-компиляции получаем машинный код.


А вы стали ли бы разбираться, в чем дело, если бы увидели такой отчет?

Тоже мне бином Ньютона. Из названия бенчмарка видно, что это числодробилка.


Как думаете, насколько правильно делать вывод о том, что Swift быстрее Go?

Под Swift находится LLVM, в котором заложены оптимизации, а компилятор Go не использует все современные инструкции процесса.


В числодробилках да.

Не очень понимаю чему тут удивляться. Видя разницу между TypeScript и JavaScript, сразу приходит на ум JIT. Asm.js тоже JavaScript, только сделан что-бы лучше джитился.

А TypeScript не сделан что бы лучше джитился.


Ну какой рантайм в числодробилках? После JIT-компиляции получаем машинный код.

Ну вот этот самый JIT, к примеру, в понятие "рантайма" входит.

Это не значит, что он в принципе не может этого делать. Одна из идей заложенных в asm.js информация о типах

Он по построению не может исполняться быстрее чем Javascript. В отличии от asm.js, в рантайме у него информация о типах полностью теряется. Следующие три строчки будут преобразованы в один и тот же Javascript:


const fn = (x : number, y : number) => x+y;
const fn = (x : string, y : string) => x+y;
const fn = (x : number | string, y : number | string) => x+y;

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

Тут есть другой нюанс — на яваскрипте легко случайно сделать полиморфный код, который будет много раз деоптимизироваться, пока компилятор не забьёт и не оставит лишь интерпретацию. А статическая типизиция мотивирует к мономорфизму, который может позволить компилятору эффективно всё заинлайнить. Правда микробенчмарки эту разницу не покажут, ибо в них идиоматичность реализации зачастую на втором месте. А вот на реальных больших проектах разница видна. Достаточно сравнить как быстр VSCode и как медлителен Atom.
Я думаю что это только предположение, которое невозможно доказать. Интуитивно с вами согласен.
Тут тогда уже вопрос к квалификации программиста, если у него код деоптимизируется. На любом языке можно написать код так, что он будет работать медленно. Просто к составлению бенчмарка для начала надо допускать только тех программистов, которые знают свой язык.
А толку от такого бенчмарка тогда? От того, что матёрый разработчик используя чёрную магию сможет сделать быструю реализацию одного простого алгоритма для бенчмарка, ваше сложное приложение, написанное средней руки программистом, в сжатые сроки, быстрее не станет.
ваше сложное приложение, написанное средней руки программистом, в сжатые сроки, быстрее не станет.
это справедливо для любого языка.
Бенчмарки показывают максимально достижимую производительность. Что важно при выборе языка для некоторых задач.
Наивно полагать, что идиоматичный код на разных языках будет иметь одинаковую производительность.

Давайте будем честными, у вас скорее всего не будет ни времени, ни специалистов для достижения максимальной производительности.
Язык должен помогать писать производительный код, что typescript безусловно и делает. Или пытается. Доказать или опровергнуть данное мнение очень трудоемко. Да и не нужно. Сильно сомневаюсь, что кто-то из-за производительности серьезно рассматривает typescript. Его сила явно в другом.
Писать все время быстрый код, как вы предлагаете программистам – это тоже плохо. Получится что-то нечитаемое и неподдерживаемое. По-моему правильно сначала писать что-то читаемое и поддерживаемое, а потом уже искать места где можно оптимизировать. Получается, что программисты пишут код в одном стиле, а бенчмарки пишутся в другом. Тоже вполне себе проблема.
Там выше был разговор про деоптимизацию, а именно, нарушение мономорфизма. Это явно говорит о неквалифицированном программисте, который плохо знает javascript.

Можно писать быстрый код, можно писать средний код, но писать говнокод то не стоит.
Это явно говорит о неквалифицированном программисте, который плохо знает javascript


Вот здесь поподробнее
А что именно подробнее? Есть мономорфизм/полиморфизм/мегаморфизм по операциям и обращению к объектам (особенно важны объекты). Описание есть на Хабре. Программист должен писать так, чтобы код без нужды не становился полимофным или мегаморфным — это ошибка.

Ну к примеру, написав const o = {width: 5, height: 5} на самом деле у Вас создадится что-то похожее на struct в плюсах, а обращение к полям такого объекта будет сразу выполняться по нужному сдвигу. Но только если вы не делаете какую-нибудь фигню, чтобы всё нарушить, например, будете в одной строчке кода обращаться к объектам разных классов (другие языки вообще чаще это не позволяют).

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

Пример по операциям — "+". Служит и для сложения, и для конкатенации. В мономорфном коде если я написал a + b, то надо, чтобы a и b всегда были числами, или всегда были строками. Тогда именно в этой строчке будет всегда выполняться одна и та же операция (сложение или конкатенация). Соответственно, с точки зрения ассемблера там всё будет просто (к примеру, тупо выполнится сложение и всё).

Кстати, javascript, если что, быстрый и ест мало памяти. А то кто мало разбираются, думают, что он медленный или жрёт много памяти (видимо, смотря, на браузеры, а они такие не из-за JS).
Меня пугает суждение о неквалифицированности.
Я не к словам придираюсь, я просто утверждаю что использование или неиспользование кода, который ведет к оптимизации на основе мономорфизма ничего не говорит о квлификации программиста от слова «совсем». А вы говоите, что это очевидно. Не очевидно.
Имеется ввиду неквалифицированность в js. В других областях или языках человек может быть квалифицирован. Если я сейчас начну писать на незнакомом языке, то я не смогу сразу же понять все его тонкости, и мой код, вероятно, будет плохим. И по такому коду строить бенчмарки будет глупо. Я могу по незнанию написать так, что код будет необоснованно медленным.
Вот вам пример. Цикл for одно время работал быстрее, чем вызов того же forEach из массива. Думаю что и сейчас ничего не поменялось, но всякое бывает. Если следовать вашей логике, то программист который впринципе использовал тогда forEach был неквалифицирован. Я не про области а про преджевременную оптимизацию
Разница между хэшем и доступом по сдвигу где-то 40 раз. Если весь код внутри for действительно работал в 40 раз медленнее, то да, программист немного неквалифицирован (хотя нужно проявлять адекватность, если это небольшой цикл, который не вызывается часто, то пойдёт, но ведь речь выше была о бенчмарках — там такая разница в производительности недопустима).

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

Кроме того, тут дело не только в процентах, а ещё и в элегантности кода. Мы отдаём эти проценты не просто так, а чтобы написать хороший код. А вот если бы программист отдавал проценты, но писал такой же по хорошести и даже хуже код, то да, такой программист с for был бы неквалифицирован, в зависимости от того, какая получалась бы просадка по производительности.

одно время
Да, думаю, квалицифированный программист должен в том числе и следить за развитием языка во времени. Необязательно знать случаи, когда конструкция стала на 10% быстрее, а вот если он ускорилась в 2 и более раз, то, думаю, это нужно знать.

Вот, к примеру, появился новый цикл с of. Первое, что я прикидываю — какая у него может быть производительность в будущем. Если понятно, что в будущем компилятор сможет прооптимизировать цикл до стандартной величины, то не так много смысла отказываться от него сейчас. Во-вторых, я меряю, какая у него производительность в данный момент. Ну и в-третьих, я слежу за блогом V8project — если цикл будет прооптимизирован, я об этом узнаю. Особенно я обращу внимание на него в том случае, если до этого он вдруг работал медленно.

В заключение могу сказать, что Вы говорили об оптимизации. А пользователь vintage говорил о деоптимизации. Это разные вещи. В случае с оптимизациями мы специально делаем так, чтобы код работал даже быстрее, чем должен. Т. е. мы были нормальным программистом, а стали супер-нормальным. А в случае, если мы, к примеру, превратим классы в хэши, то код станет работать медленнее, чем должен. Т. е. мы были нормальным программистом, а стали плохим. Преждевременная оптимизация чаще не нужна, но это не значит, что программист должен убивать свой код и делать его в 10–100 раз медленнее, чем должен даже без оптимизации.
Единственный возможный путь к ускорению за счет статической типизации — интерпретация Typescript напрямую, без преобразования в Javascript. Но так никто делать не умеет, и пока что не собирается.

Эмм… Не совсем
Так там же все равно в итоге V8 используется. А значит, и преобразование в Javascript есть, и типы никто не использует для оптимизаций.
Так там же все равно в итоге V8 используется.

Да. И в итоге в тот же ассемблер компилируется.
А значит, и преобразование в Javascript есть, и типы никто не использует для оптимизаций.

Leap of logic, этого оттуда не следует.
Leap of logic, этого оттуда не следует.

Как вы объясните это:

For deno to execute typescript, it must first compile it to JS. A warm startup is when deno has a cached JS output already, so it should be fast because it bypasses the TS compiler. A cold startup is when deno must compile from scratch.
Тем, что это не следует из «компилируется тем же V8»

Ответить могу тем, что да — сейчас не используется, но в будущем почему нет? Часть кода компилируем не в жс, в сразу в машинный код. Процесс-то не мгновенный. Потому что иначе во всем проекте мало смысла.

Технически говоря, покуда мы не знаем (или знаем и я что-то просмотрел? Там есть мистическая строчка tsc, но все же) что там этот ts компилировало, можно предположить, что так же этот компилятор использовал какие-то трюки для оптимизации, например, заинлайнив метод doCacl, использовал SIMD или вообще переписал все под asm.js или вообще wasm.


Правда никто не мешает тоже самое сделать и с js (типы только самому придется выводить).


P.S. Как заметили ниже, в коде на ts просто используются воркеры вместо процессов в js.

верно, эти три строчки будут преобразованы в один и тот же JavaScript

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

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

Какой ключ у tsc делает инлайнинг константных функций? Я почему-то не наблюдаю подобного поведения.

Вы правы. Оптимизацию провел webpack. Написал я полный бред!

Ну что же, впредь мне наука — проверяй гипотезы тщательнее и не спеши писать посты поздно ночью!
webpack тоже ничего подобного не умеет.
репозиторий с настройками

Тест уверенно воспроизводится на моей машине, при установке флага minimize: false в конфиге вебпака — инлайнинга нет. Если же в optimization вообще ничего нет, как в репо, то инлайнинг есть
причем делает это webpack по дефолту
Это не webpack делает, а внешняя библиотека terser.
это уже схоластика. В документации terser-plugin описан как внешняя зависимость и есть даже указание на его install

Но по факту, посмотрите package.json, мы заказываем инсталл только webpack, webpack-server и webpack-cli, и внезапно оказывается, что у нас скрыто подключается terser. Почему тогда мы должны говорить «это делает не вебпак?» Ведь в депенденси нет терсера?

тогда давайте сделаем следующий шаг — «этот комментарий набираю не я, а мои пальцы». )
Этот комментарий набираю не я, а человечество.
знаете, если вы успели прочитать мою удаленную статью, то я нашел причину разрыва в скорости. Там инлайнинг играет очень крохотную роль. Разница в том, что ES5 на моих браузерах исполнялась быстрее, чем ES6. Это ввело меня в заблуждение и в цепь поспешных логических выводов.

А насчет философии иерархических включений — надеюсь, что я как человечество, рано или поздно перестану бить сам себе морду, а то получается какое-то сумасшествие. Наверное, поэтому, другие человечества и не спешат заходить в мою солнечную систему и здороваться с таким соседом )
А что там было из es6?
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Не проверяю корректность маркетинговых бенчмарков, потому что всё равно бессмысленно. Ибо сформировать нужную картину можно не подтасовывая факты, а выдав их в нужном порядке и количестве.
Предположительно ТС просто изначально не очень понял что сравниваются формально похожие, но всё же разные реализации. т.е. выдать эффективную, но соответствующую требованиям реализацию — задача сообщества языка.

Этот тест открыт для всех, если есть уверенность в том что JS должен не отставать от TS, то надо просто отправить туда свой вариант и его добавят. И несправедливость будет исправлена.

Чтобы удобно следить — для этого там нумеруют конкретную реализацию, так как из-за смены компилятора или библиотеки или ещё чего-то, можно обнаружить, что конкретная реализация неожиданно разогналась или отстала.

По-пунктам:
1) TS vs JS, надо просто отправить код, которому вы верите и он будет принят. В статье много говорится об этом тесте, но причина почему так — не раскрывается. О каком рефакторинге идёт речь — не очень понятно: если задача — поддержать код будущими интернами — то эти тесты не про это.
2) Rust vs Rust, просто игнорируйте версию, которая в данный момент отстала, если она не имеет для вас значение.
3) Swift vs Go, из данного теста очевидно что в настоящий момент Swift опережает Go в реализации mandelbrot и ничего больше, чтобы ~ представить производительность на более широком кругу задач — то надо посмотреть на и на другие тесты. Какие-то из них завязаны на реализаций hashmap, другие — на деревья, большинство — на параллельное выполнение. Все в большинстве относительно простые. Если интересуют более комплексные тесты — то их надо искать не на этом сайте, но тем не менее какое-то относительно точное представление о производительности языков он даёт.

Мало того, финальный документ на их странице показывает свечу с распределением результатов всех тестов для конкретного языка, где можно заметить, что в целом производительность не так сильно отличается, как кажется если смотреть только на топовые цифры.
TS vs JS, надо просто отправить код, которому вы верите и он будет принят.
Как может TS быть быстрее JS? Что это сравнение вообще показывает? Я не вижу причины существование этого теста. Полчить правку просто, достаточно TS скопилировать в JS.

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

Rust vs Rust, просто игнорируйте версию, которая в данный момент отстала, если она не имеет для вас значение.
Не могу проигнорировать. Если посмотреть внимательно, то самая быстрая версия в 2 раза быстрее чем предыдущая. А swift быстрее go меньше чем в два раза. Где гарантия, что кто-то кто понимает в go не напишет тест, который ускорит версию Go в два раза? Ведь это уже было с Rust.

Swift vs Go, из данного теста очевидно что в настоящий момент Swift опережает Go в реализации mandelbrot и ничего больше
Вот это как раз неочевидно. Про это и статья. Очевидно только то, что программист на Swift написал более быстрый код.

достаточно TS скопилировать в JS

Я согласен, именно это и надо сделать и отправить, к сожалению, вопрос JS vs TS меня не сильно волнует, чтобы заняться исправлением этого самому.

Где гарантия, что кто-то кто понимает в go не напишет тест, который ускорит версию Go в два раза

Как это устроено вполне понятно — чем больше вариантов решений для конкретного языка — тем больше можно сделать вывод, что код _приближается_ к оптимальному. Не очень понятно кто кому какие гарантии, в ежедневно меняющимся IT, тут должен давать. Тест показывает то что показывает на настоящий момент. «Где гарантии, что через 5 лет не выйдет специальный процессор под JS, на котором JS обгонит C?» — нет таких гарантий.

Очевидно только то, что программист на Swift написал более быстрый код.

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

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

Тест показывает, что в настоящий момент конкретная программа на swift быстрее конкретной программы на go. Но тест не показывает, что в настоящий момент swift быстрее go.

вы подняли хорошую тему. Действительно, TS должен превращаться в аналогичный JS. И все-таки разница в скорости появляется — из-за того, что транспайлер TypeScript пытается оптимизировать производительность кода. Я написал одинаковый код на TS и JS, и первый оказался быстрее. Причина — в инлайнинге функций.

Подробности, код и скриншоты — в короткой заметке
habr.com/post/433230

Буду рад, если вы проверите тесты, и убедитесь сами.
Вкратце: я был неправ и сонный, смущал народ, выдавал непроверенные теории за факты.

Ту оптимизацию, что я описал, проводит webpack

Другими словами, если workflow один и тот же, разницы между тестами на разных языках быть не должно.
«Грузины лучше чем Армяне»
— Windows лучше, чем Linux!
— Чем?
— Чем Linux!
©

А, простите, чего заминусовали-то? Это ж тоже про веру бенчмаркам

Кстати, Go быстрее чем Rust

Это был сарказм?))

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

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

Oh shi~, я думал это исходная статья про mail :D Минусы не мои если что
Он — это человек, которому вы отвечаете на сообщение? :)

А, выше уже написали. В общем, вышло забавно.
А чему тут удивляться? Кто-то, кто имел достаточно опыта, но не достаточно ума, где-то, на вопрос новичка, посмотревшего лишь несколько уроков на youtube, «что делать дальше», ответил — идти в опенсорс или создавать свой сервис. И все как один это подхватили и словно боты начали повторять слова не лишенных смысла. И вот результат.

Бенчмарки между языками обычно знак скудоумия и бенчмаркер обычно силен в одном своем маленьком мирке=языке, отсюда и идут перлы аля Свифт быстрее Go, Go быстрее Java. Вот когда "медленная" Java на ваших глазах развернет цикл, векторизует в AVX, выравняет данные для лучшей загрузки в регистры и все это в произойдет в момент выполнения когда программа сама поймет что это имеет смысл (tiered jit) в отличие от АОТ — вы все еще будете бенчмаркать Go vs Java?

Программисты помешаны на скорости исполнения программ. Мы следим за скоростью даже там, где эта скорость не очень-то и важна.

Ах, если бы…
К сожалению, мы живём в мире, где всем (ладно, почти) глубочайше насрать на производительность порождаемых ими монструозных уродцев.

О да, последние несколько проектов(так повезло) спрашиваю себя,
почему на рынке еще не появилось ниши "читателей кода".
"Аудит самих себя" не так часто работает. На последних местах — одно и то же:


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


Наконец, приходит время смотреть проект:
читать код, "выписывать свои мысли, чтобы сформировать задачи".


И совершенно неочевидно, что делать, если все "очень плохо". В голове две мысли — плевать начальника и стучаться к боссу повыше, либо бежать.


За оклад балансировать между корпоративной этикой и здравым смыслом может не каждый.

Не знаю, я постоянно встречаю обратную ситуацию. Человеку нужно какой-нибудь веб-сервер написать, с БД и сетевыми запросами, так он начинает экономить на лишних копированиях восьмибайтных структур, «не, деление это дорого, надо сдвигами только», начинают спрашивать, как вынести запросы ДНС в отдельный поток, чтобы они быстрее работали… А клиент всё сидит и ждет, когда софтину напишут.
Про мир в целом согласен. Один electron чего стоит. Но это не значит, что людей не беспокоит эта проблема. Так что все по классике. Чем больше беспокоимся, тем медленней работает.
Потому что если и экономят, то, чаще всего, не на том, что надо. Часто наблюдаю совершенно замечательные ситуации, когда человек упорно тюнит запрос, который выполняется две секунды раз в сутки, а запрос, который полсекунды, но дцать раз за одно обращение к бэкэнду — игнорируется, потому что «ну он жеж и так быстрый».
Посмотрел реализации на Java для пары задач — вынес для себя один вывод:
Если нужно много операций с числами без потери точности то вместо BigInteger нужно использовать стороннюю библиотеку — так заметно быстрее и меньше памяти требует.
В части сравнений между языками / платформами — видно как рантаймы отличаются между языками
Зарегистрируйтесь на Хабре, чтобы оставить комментарий