Comments 62
Я правильно понимаю, что, теоретически, это может дать прирост и в интерпретаторах других браузеров?
0
И практически. Весь этот текст можно сжать до фразы «Пишем как можно более типизированно» (типизированные массивы, не перегруженные функции, статический набор полей у объектов).
Тот же TypeScript кроме сахаров помогает писать быстрый код за счет статической проверки типов(именно помогает, а не делает).
Тот же TypeScript кроме сахаров помогает писать быстрый код за счет статической проверки типов(именно помогает, а не делает).
+11
Почему JavaScript изначально такой? Как хорошо было бы, если бы он был типизированным.
+1
Так исторически сложилось. (с)
0
UFO just landed and posted this here
Есть Dart…
0
Он есть, но его и нет. Точнее он пока в стадии «Посмотреть и поиграться», а JavaScript есть уже сейчас и с ним надо что-то делать.
0
Ну как, всё, кроме HTTP-клиента/сервера и сокетов для нативной части реализовали. Библиотека обширная, интероп с JS умеет. Так что можно использовать.
0
К сожалению, это только хром. Трансляции в JS он, конечно, поддается, но с костылями. Например, попробуйте транслировать генераторы в JS кроме них есть еще много других примеров. Dart язык очень хороший, но распостраненность — это его огромная проблема (которая в ближейшие лет 5 точно не решится).
0
как это только хром? постоянно гоняем тесты dart2js на FF, Safari, IE: build.chromium.org/p/client.dart/console
0
dart2js конечно хорошо, но в Dart есть такие штуки не свойственные для JavaScript и dart2js делает их костылями. Нет генераторов, нет Image, нет декларативных классов, нет честных изолятов (изоляты воркерах не могут трогать DOM). Ты же сам прекрасно знаешь их фундаментальные различия :)
Dart это очень хорошо, но я бы пока не стал его использовать в продакшене.
Dart это очень хорошо, но я бы пока не стал его использовать в продакшене.
0
> К сожалению, это только хром. Трансляции в JS он, конечно, поддается, но с костылями.
Байка. Рекомендую почитать вот этот пост Сета Лэдда: blog.sethladd.com/2012/10/9-dart-myths-debunked.html
Байка. Рекомендую почитать вот этот пост Сета Лэдда: blog.sethladd.com/2012/10/9-dart-myths-debunked.html
0
Вот AS3 тоже ECMAScript, но с типами — совсем другая песня :)
0
UFO just landed and posted this here
Сначала мы дадим вам возможность сохранять в переменную значение любого типа.
Потом начнем бить по рукам, чтобы вы этого не делали.
Потом начнем бить по рукам, чтобы вы этого не делали.
-3
UFO just landed and posted this here
Это не упрек, это на тему, что, если плохо придумано сначала, то надо сломать и переделать.
-1
Не бить по рукам, а всего лишь толсто намекать, что использование этой опции имеет очень ненулевую цену…
+1
Местами не правильно перевели, например:
1. Массивы бывают двух видов — хранящие 31 битные инты и указатели на другие обьекты(этой разницей бит и кушается) и только числа двойной точности.
Чем плохо — был массив с двумя интами, под него выделилилось место для хранения 4х. Вы добавили double и массив перепаковался в типизированный. Старые данные уходят в GC. Добавили строку — обратная перепаковка. Ваш double теперь доступен через указатель, что сильно медленно
2. Полиморфные функции не медленее чем мономорфные. Это буду две разные функции, каждая из которых потребует своей оптимизации( 0.5-1мсек на функцию, это не мало). IC(inline cache) может чуть раньше выбрать какую он будет использовать.
3. Огромная Сила в inline функциях! Жалко что хром не инлайнит функции которые требуют переключение контекста. Да, именно в JS функциональное программирование реально быстрее чем старый добрый ООП.
Вообще профилирование через d8 или запуск хрома с флагами чтука относительно бесполезная. Позволяет оттюнить только синтетические примеры и реально узкие места.
1. Массивы бывают двух видов — хранящие 31 битные инты и указатели на другие обьекты(этой разницей бит и кушается) и только числа двойной точности.
Чем плохо — был массив с двумя интами, под него выделилилось место для хранения 4х. Вы добавили double и массив перепаковался в типизированный. Старые данные уходят в GC. Добавили строку — обратная перепаковка. Ваш double теперь доступен через указатель, что сильно медленно
2. Полиморфные функции не медленее чем мономорфные. Это буду две разные функции, каждая из которых потребует своей оптимизации( 0.5-1мсек на функцию, это не мало). IC(inline cache) может чуть раньше выбрать какую он будет использовать.
3. Огромная Сила в inline функциях! Жалко что хром не инлайнит функции которые требуют переключение контекста. Да, именно в JS функциональное программирование реально быстрее чем старый добрый ООП.
Вообще профилирование через d8 или запуск хрома с флагами чтука относительно бесполезная. Позволяет оттюнить только синтетические примеры и реально узкие места.
+3
1. По типу содержимого быстрые элементы бывают трех видов и трансформируются в одном направлении от менее общих к более общим: smi (small integer) -> double -> object. Бывают еще дырявые (holey) и непрерывные (packed). Еще бывают медленные элементы — представляются словарем.
2. Рекомендация соблюдать мономорфизм относится не к функциям, а к отдельным операциям, например, оператору умножения, оператору [] или вызову метода. Операции работают быстрее, когда они мономорфны — выполнятся над объектами одного и того же типа/скрытого класса. Как вы определяете «полиморфную функцию»?
3. V8 инлайнит функции, которые требуют переключения контекста на ia32 (Mac, Windows), но не инлайнит на x64/arm. Что касается функционального программирования, то зависит от того какие именно паттерны мы сравниваем. В большинстве случаев ООП основанное на связке constructor + prototype chain имеет больше шансов быть хорошо заоптимизированным. Можно почитать мой блог о том, какие именно проблемы возникают если опираться на замыкания: mrale.ph/blog/2012/09/23/grokking-v8-closures-for-fun.html
А собственно кроме узких мест ничего никогда тюнить и не надо. Все советы по оптимизации бесполезны в 99% случаев, пока вы не наткнетесь на случай попадающий в злые 1%, где надо костьми лечь но выжать все что можно.
2. Рекомендация соблюдать мономорфизм относится не к функциям, а к отдельным операциям, например, оператору умножения, оператору [] или вызову метода. Операции работают быстрее, когда они мономорфны — выполнятся над объектами одного и того же типа/скрытого класса. Как вы определяете «полиморфную функцию»?
3. V8 инлайнит функции, которые требуют переключения контекста на ia32 (Mac, Windows), но не инлайнит на x64/arm. Что касается функционального программирования, то зависит от того какие именно паттерны мы сравниваем. В большинстве случаев ООП основанное на связке constructor + prototype chain имеет больше шансов быть хорошо заоптимизированным. Можно почитать мой блог о том, какие именно проблемы возникают если опираться на замыкания: mrale.ph/blog/2012/09/23/grokking-v8-closures-for-fun.html
А собственно кроме узких мест ничего никогда тюнить и не надо. Все советы по оптимизации бесполезны в 99% случаев, пока вы не наткнетесь на случай попадающий в злые 1%, где надо костьми лечь но выжать все что можно.
+2
Вы давно видели 32х битные Маки?
Долго копал и свой код, и исходники v8 чтобы понять как можно заставить заинланиться некоторые мои функции (например математические).
Но у вас в блоге заметил странную магию с «use strict», который не дает захватывать контекст.
Можете эту магию прокоментировать, и вообще дать пару разъяснений про strict mode. Это лексический режим, или оно влияет и на генерируемый ассемблер?
Долго копал и свой код, и исходники v8 чтобы понять как можно заставить заинланиться некоторые мои функции (например математические).
Но у вас в блоге заметил странную магию с «use strict», который не дает захватывать контекст.
function sk(x, y) { // x and y are not context allocated
"use strict";
return arguments[0] * arguments[1];
}
Можете эту магию прокоментировать, и вообще дать пару разъяснений про strict mode. Это лексический режим, или оно влияет и на генерируемый ассемблер?
0
> Вы давно видели 32х битные Маки?
Chrome на Mac по сей день 32-битный
64-битная сборка только на Linux используется AFAIK
> Но у вас в блоге заметил странную магию с «use strict», который не дает захватывать контекст.
В данном конкретном примере
Strict mode описан в стандарте: es5.github.com/#C
> как можно заставить заинланиться некоторые мои функции (например математические).
Если вы набросаете примеры кода, то можно будет обсудить почему что-то не инлайнится и какая будет польза от инлайна :-)
Chrome на Mac по сей день 32-битный
omega ~ ∳ file /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome
/Applications/Google Chrome.app/Contents/MacOS/Google Chrome: Mach-O executable i386
64-битная сборка только на Linux используется AFAIK
> Но у вас в блоге заметил странную магию с «use strict», который не дает захватывать контекст.
В данном конкретном примере
"use strict"
разрывает связь между arguments
и формальными параметрами. Это убирает создание контекста и позволяет инлайнить этот код (если функция создает контекст, то такую пока V8 не инлайнит).Strict mode описан в стандарте: es5.github.com/#C
> как можно заставить заинланиться некоторые мои функции (например математические).
Если вы набросаете примеры кода, то можно будет обсудить почему что-то не инлайнится и какая будет польза от инлайна :-)
+1
пример банален
Кстати, пользуясь, случаяем хотел бы уточнить насчет хранения двордов. Что же лучше — массив(который будет создан уже перепакованным?) или хэш с .x\.y(который тоже вообще бинарная структура вроде)?
var vector = {
add: function (a,b){
return [a[0]+b[0],a[1]+b[1]]
}
}
//и где-то в совершенно другом месте vector.add не инлайнится
При этом, если бы я использовал просто функцию vector_add в глобальном scope - инлайн был бы возможен.
Кстати, пользуясь, случаяем хотел бы уточнить насчет хранения двордов. Что же лучше — массив(который будет создан уже перепакованным?) или хэш с .x\.y(который тоже вообще бинарная структура вроде)?
0
эта функция не заинлайнится из-за array literal даже если будет в глобальном scope: code.google.com/p/v8/issues/detail?id=1322
если vector существует в единственном числе, то тут разницы между глобальным и не глобальным scope не должно быть.
Хранение 32-битных величин сложный вопрос. На ia32 те из них которые не влезают в smi (31-bit signed integer) превратятся в полновесные числа с плавающей точкой. Зависит от многих факторов: как много тех кто не влезает в 31бит, как они будут использоваться и т.д. Int32Array может оказаться оптимальным в некоторых случаях.
если vector существует в единственном числе, то тут разницы между глобальным и не глобальным scope не должно быть.
Хранение 32-битных величин сложный вопрос. На ia32 те из них которые не влезают в smi (31-bit signed integer) превратятся в полновесные числа с плавающей точкой. Зависит от многих факторов: как много тех кто не влезает в 31бит, как они будут использоваться и т.д. Int32Array может оказаться оптимальным в некоторых случаях.
0
Можно поподробнее про силу инлайна?
0
var a = [1, 2, 3, 4];
// Если выполнять это честно, то функция будет вызвана на каждом элементе - это дорого
// Но такая запись более читаема
a.forEach(function (item) {
console.log(item);
});
// Такие экспрешены инлайнится (где это возможно) в стейтмент for () {}
for (var i = 0; i < a.length; i++) {
console.log(a[i]);
}
0
только вот такой оптимизации V8 не делает пока :-)
0
В общем самое вкусное покуда не инлайнится.
0
А тогда каким образом это работает быстро? Не над каждым же элементом честно функция вызывается.
0
следует определить понятие быстро :-)
над каждым элементом функция честно вызывается. в зависимости от того, что функция делает цена этого вызова может быть заметна, а может быть амортизированна и не очень заметна.
над каждым элементом функция честно вызывается. в зависимости от того, что функция делает цена этого вызова может быть заметна, а может быть амортизированна и не очень заметна.
0
быстро всмысле сопоставимо со стейтментом for
0
ну по сравнению с циклом
for
если зарядить на длинном массиве, много-много раз пустую функцию то будет видна цена вызова.0
Кстати, а что мешает заинлайнить такой цикл? (понятно, что мой пример был предельно тривиальный)
0
Другой вопрос, а что мешает заинлайнить пустые функции? Точнее привести их к виду — не вызывать, все undefined возвращать. Ведь функции — immutable и тело у них самом собой появиться не может.
0
А что нужно делать вместо удаления элементов из массивов?
0
Либо использовать хэши, либо закрывать дырку в массиве, либо ответить на вопрос зачем удаляем.
0
А вы сами используете массивы, только когда не предполагается удалять из них элементы?
0
Я использую массивы для разных целей.
Но никогда не оставляю в них дырки.
Тут лучше обойтись хэшом.
Но никогда не оставляю в них дырки.
Тут лучше обойтись хэшом.
0
А удаление с конца массива тоже оставляет дырки в его внутреннем представлении? Где можно подробнее почитать на этот счет?
0
когда говорится, что лучше не удалять элементы, имеется ввиду удаление многих элементво из середины оператором delete.
+1
вы уверены про delete? он не удаляет элемент, а прописывает undefined
splice удаляет элементы из середины
splice удаляет элементы из середины
0
мы, видимо, по разному определяем понятие удалить.
прежде всего
дырки это та проблема, которой рекомендации рекомендуют избегать, чтение из дырки требует поиска свойства через цепочку прототипов и оптимизированный код не любит этого и просто деоптимизируется. К тому же если у вас в массиве много дырок, то V8 может внезапно решить, что память важнее производительности и ради экономии места превратит длинный дырявый массив в словарь.
прежде всего
delete
не прописывает undefined
, он удаляет свойство полностью оставляя вместо него дырку. разницу просто увидеть на примере кода:a = [1];
b = [1];
Array.prototype[0] = 42;
console.log(a[0] + " " + b[0]); // 1 1
delete a[0];
b[0] = undefined;
console.log(a[0] + " " + b[0]); // 42 undefined
дырки это та проблема, которой рекомендации рекомендуют избегать, чтение из дырки требует поиска свойства через цепочку прототипов и оптимизированный код не любит этого и просто деоптимизируется. К тому же если у вас в массиве много дырок, то V8 может внезапно решить, что память важнее производительности и ради экономии места превратит длинный дырявый массив в словарь.
splice
же, который удаляет и сдвигает элементы не оставляет после себя дырок, поэтому безобиден в данном отношении. Следует, впрочем, всегда помнить, что он имеет линейную сложность по количеству сдвигаемых элементов.+3
Можно юзать как стек или очередь.
0
А что нужно делать вместо удаления элементов из массивов?Удалять-то можно; а нужно не оставлять дырки.
Поэтому вместо «delete arrayName[index]» следует использовать
-1
я бы сказал, что это спорная рекомендация и они совсем не эквивалентны. все конечно же зависит от конкретного кода,
splice
, например, линейная операция по количеству сдвигаемых элементов. в каких-то случаях может лучше arr[i] = null;
делать (хоть оно и не эквивалентно delete
)+1
Я как раз и использую
splice
. Однако он медленнее, чем просто устанавливать значение равным null, либо делать delete
. Но ведь это тоже не всегда приемлимо. Было бы хорошо услышать реальные примеры задач и те цифры, которые мы выигрываем/проигрываем, используя один или другой метод.0
Спасибо за перевод! Собрал d8, но похоже это было самой простой задачей)
--trace-opt, --trace-deopt — ничего не выводят, и так и эдак пробовал. Есть какой-нибудь код, который гарантировано выведет инфу?
--trace-bailout — похоже выпилили. В Changelog (Version 3.13.4): Print reason for disabling optimization. Kill --trace-bailout flag. По крайней мере сейчас, ругается на несуществующий флаг.
--trace-opt, --trace-deopt — ничего не выводят, и так и эдак пробовал. Есть какой-нибудь код, который гарантировано выведет инфу?
--trace-bailout — похоже выпилили. В Changelog (Version 3.13.4): Print reason for disabling optimization. Kill --trace-bailout flag. По крайней мере сейчас, ругается на несуществующий флаг.
0
UFO just landed and posted this here
> В частности, оптимизирующий компилятор пропускает любые функции, содержащие блоки try/catch
Интересно, значит ли это, что jQuery толком не оптимизируется? или для него сделано исключение?
Просто у меня стойкая ассоциация в мозгу, что
Интересно, значит ли это, что jQuery толком не оптимизируется? или для него сделано исключение?
Просто у меня стойкая ассоциация в мозгу, что
jQuery('...') === try { jQuery('..') } catech(e) {};
0
> Инициализируйте все объекты в конструкторах, чтобы они как можно меньше менялись в дальнейшем.
Спасибо, погуглил, ускорил стандартный setTimeout в node.js на 15-20%.
github.com/joyent/node/issues/4182
Спасибо, погуглил, ускорил стандартный setTimeout в node.js на 15-20%.
github.com/joyent/node/issues/4182
0
Sign up to leave a comment.
Оптимизируем производительность JavaScript для V8