Комментарии 38
> Многие заметят и скажут: будет такое же время. А не тут то было. Выдал 25. Хотя массивы создавались столько же раз.
Массивы что там, что здесь создаются только при выполнении этой функции.
А вот сама функция в случае ее выноса во вне, создается один раз, а когда вы объявляете ее в объекте — создается каждый раз.
А вообще, вы не открыли америку.
Массивы что там, что здесь создаются только при выполнении этой функции.
А вот сама функция в случае ее выноса во вне, создается один раз, а когда вы объявляете ее в объекте — создается каждый раз.
А вообще, вы не открыли америку.
Хотел поковыряться, но у меня почему-то и ваш начальный код, и ваш конечный код выдают одинаковое время, равное 20 мс, вот ссылка:
http://jsbin.com/hevikonuhu/edit?html,console,output
Возможно, я что-то делаю не так?
http://jsbin.com/hevikonuhu/edit?html,console,output
Возможно, я что-то делаю не так?
Попробуйте запустить на Node.js. Не знаю почему, но в браузере значительной разницы не вижу тоже. У меня выдает 776 для начального варианта и 716 для конечного.
А какая версия ноды используется? Может просто в браузере более свежая версия движка V8?
Тестировал в 4.2.2 (LTS). Сотрудник проводил на 5.x и тоже было такое.
Хм, действительно странно. Где первая оптимизация с 1908 до 16мс.
Это же просто замыкания.
Создание нового замыканя потребляет ресурсы (ЦП+ОЗУ) для захвата области видимости, должно быть очевидно.
Нужна максимальня производительность — избегайте замыканий в любом виде.
Создание нового замыканя потребляет ресурсы (ЦП+ОЗУ) для захвата области видимости, должно быть очевидно.
Нужна максимальня производительность — избегайте замыканий в любом виде.
Так в замыкании не используются переменные, которые выше.
Нашел оптимизацию этой особенности: везде в замыканиях используйте new Object() / new Array()
Немного не в тему, для замеров времени можно упростить:
console.time('first test');
тестируемый код
console.timeEnd('first test');
- канонично в node.js использовать process.hrtime() для измерения относительных промежутков времени — функция значительно точнее.
const start = process.hrtime(); // do op const end = process.hrtime(start); console.info("Время исполнения (hr): %ds %dms", end[0], end[1]/1000000);
var a
внутри циклаfor
— постоянное переобъявление переменной, используйтеlet
если нужно ограничить scope, или объявите до цикла
- штудируем https://github.com/petkaantonov/bluebird/wiki/Optimization-killers касательно оптимизаций — многие вопросы отпадут сами собой
О господи, очередные откровения «как нам ускорить JS-код».
Подымите руку, у кого в стандартной бизнес-логике (сходить в три бэкенда и сшаблонизировать данные) есть самописные циклы на 100 тысяч итераций.
Подымите руку, у кого в стандартной бизнес-логике (сходить в три бэкенда и сшаблонизировать данные) есть самописные циклы на 100 тысяч итераций.
Зря вы так. HTML5 предоставляет широчайшие возможности в области работы с канвой. И в модулях отрисовки графики вполне вероятны "битвы" за каждую миллисекунду времени.
Тут одно из двух. Или ты пользуешься готовой библиотекой, а клиентскую логику пишешь как удобнее и понятнее, а не как «производительнее».
Или ты сам разрабатываешь такую библиотеку, и тогда подобные советы у тебя вызывают только недоумении «как этого можно не знать».
Новичкам нужно запомнить ровно одно правило: не занимайся преждевременной оптимизацией.
Или ты сам разрабатываешь такую библиотеку, и тогда подобные советы у тебя вызывают только недоумении «как этого можно не знать».
Новичкам нужно запомнить ровно одно правило: не занимайся преждевременной оптимизацией.
Или ты сам разрабатываешь такую библиотеку, и тогда подобные советы у тебя вызывают только недоумении «как этого можно не знать».Давайте без лишнего пафоса. Можно писать библиотеку или некую логику, которая будет вызываться и чаще чем миллион раз, и не знать таких вещей. В конце концов, когда говорят об экономии на спичках, обычно упоминают об этом, а не об new `Object vs {}`.
А вы не думали что функция которая возвращает indexOf из глобальной переменной могла просто заинлайниться, убрав в этом случае оверхед на лишних миллион созданий/вызовов внутренней функции?
Зашел на страницу статьи из-за горячего заголовка. Ожидал новую тру-практику. На деле же — просто разбор собственных полетов.
Во-первых, js-движку по барабану динамическая ли функция или не динамическая. По состоянию, важному для производительности, можно выделить откомпилированные функции и неоткомпилированные. Обычно функции компилируются при первом выполнении. Существуют и способы определения откомпилированных функций и без выполнения функции. Например, через
По поводу массивов. Вы правильно заметили, создание массива съедает немного производительности. Вы забыли учесть, что имеет место быть не менее трудоемкая задача — утилизация массива. В вашем же примере основная производительность тратится на постоянное изменение размера массива. По уму, размер массива надо задавать при создании. И, по возможности, следует пользоваться типизированными массивами.
Стоит также отметить, что ни в коем случае нельзя пользоваться большими массивами через замыкания или параметры вызова функций. Это переполняет стек процесса и создает немалую нагрузку на процессор.
Во-первых, js-движку по барабану динамическая ли функция или не динамическая. По состоянию, важному для производительности, можно выделить откомпилированные функции и неоткомпилированные. Обычно функции компилируются при первом выполнении. Существуют и способы определения откомпилированных функций и без выполнения функции. Например, через
new Function(..)
.По поводу массивов. Вы правильно заметили, создание массива съедает немного производительности. Вы забыли учесть, что имеет место быть не менее трудоемкая задача — утилизация массива. В вашем же примере основная производительность тратится на постоянное изменение размера массива. По уму, размер массива надо задавать при создании. И, по возможности, следует пользоваться типизированными массивами.
Стоит также отметить, что ни в коем случае нельзя пользоваться большими массивами через замыкания или параметры вызова функций. Это переполняет стек процесса и создает немалую нагрузку на процессор.
Как использование массивов через замыкания или аргументы влияет на стек процесса?
Подробнее здесь https://habrahabr.ru/company/plarium/blog/277129/
По поводу аргументов — у меня речь шла именно про большИе массивы. Разумеется, никто не запрещает передавать небольшие объекты/массивы, например, в качестве конфига. Дело в том, что в некоторых случаях использования массивов в качестве аргументов вызова функции, доступ к данным массива осуществляется не как через ссылку на исходный массив-объект, а происходит копирование массива и доступ к данным осуществляется уже к копии массива.
По поводу аргументов — у меня речь шла именно про большИе массивы. Разумеется, никто не запрещает передавать небольшие объекты/массивы, например, в качестве конфига. Дело в том, что в некоторых случаях использования массивов в качестве аргументов вызова функции, доступ к данным массива осуществляется не как через ссылку на исходный массив-объект, а происходит копирование массива и доступ к данным осуществляется уже к копии массива.
Не подскажете, где почитать про копирование массива при подстановке в функцию?
внимательно перечитал статью — не нашел там упоминания о передаче массива по значению. Вообще в моем понимании javascript этого не должно происходить ни при каком случае — объекты всегда передаются по ссылке, скаляры — по значению.
если я не прав — мое понимание javascript требует пересмотра с основ.
если я не прав — мое понимание javascript требует пересмотра с основ.
Вот так живешь живешь, а потом оказывается что в js массивы не по ссылкам передаются, а по значениям. Вы либо выразили свою мысль не правильно, либо несете что то из разряда фантастики.
Отвечу на один вопрос, заданный несколько раз выше, здесь.
Не помню точно, как дошел до этой практики. Уже тоже пруф найти не могу. Помню, дело было за долго до nodejs. Делали web-интерфейс на ExtJS для несложной но ёмкой БД. При активной передаче некоторых массивов описанным выше способом вешался весь браузер.
Сейчас похожее поведение может проявляться при вызовах из JS функций с кодом, например, написанных на Си.
Не помню точно, как дошел до этой практики. Уже тоже пруф найти не могу. Помню, дело было за долго до nodejs. Делали web-интерфейс на ExtJS для несложной но ёмкой БД. При активной передаче некоторых массивов описанным выше способом вешался весь браузер.
Сейчас похожее поведение может проявляться при вызовах из JS функций с кодом, например, написанных на Си.
Конечно, оптимизация функций имеет место быть (в некоторых случаях она необходима), но в общем случае оптимизация архитектуры приложения даст вам намного больший прирост в производительности, чем чрезмерная оптимизация тела некоторых функций.
Статья интересная, но на практике это пригодится для узкого круга задач, и при условии что подходящего инструмента для решения задачи нет.
Если есть люди, которые столкнулись с такими задачами, отпишитесь в комментарии, пожалуйста.
Статья интересная, но на практике это пригодится для узкого круга задач, и при условии что подходящего инструмента для решения задачи нет.
Если есть люди, которые столкнулись с такими задачами, отпишитесь в комментарии, пожалуйста.
Нельзя делать выводы на основе простых измерений, надо хотя бы профилировать и пытаться понять, что же на самом-то деле происходит внутри. Иначе получаются неправильные выводы.
Дело здесь в следующем — создание функций, которые содержат в себе литералы (например, array literal или там object literal), это более тяжелая операция по сравнению с созданием функций, которые в себе литералов не содержат.
Если взять и просто сравнить два профиля, то все тайное становится явным
В первом случае мы ходим много в среду исполнения и там занимаемся всякой тяжелой и малополезной работой (например, клонированием массива литералов привязанного к замыканию), а во втором случае мы быстренько создаем замыкание с помощью
Дело здесь в следующем — создание функций, которые содержат в себе литералы (например, array literal или там object literal), это более тяжелая операция по сравнению с созданием функций, которые в себе литералов не содержат.
Если взять и просто сравнить два профиля, то все тайное становится явным
function find(val){
function index (value) {
return [1, 2, 3].indexOf(value);
}
return index(val);
}
8.29% 67 | LazyCompile:*InnerArrayIndexOf native array.js:1020 * 7.67% 62 | v8::internal::JSFunction::set_literals * 7.05% 57 | v8::internal::Factory::NewFunctionFromSharedFunctionInfo * 5.81% 47 | v8::internal::Factory::NewFunction * 4.58% 37 | v8::internal::Factory::New<v8::internal::JSFunction * 4.33% 35 | v8::internal::Runtime_NewClosure 4.21% 34 | Stub:FastCloneShallowArrayStub 4.08% 33 | v8::internal::Heap::AllocateRaw 3.34% 27 | LazyCompile:~index test.js:2 * 3.34% 27 | v8::internal::Factory::NewFunctionFromSharedFunctionInfo 3.34% 27 | Builtin:ArgumentsAdaptorTrampoline 3.09% 25 | v8::internal::Heap::Allocate * 3.09% 25 | v8::internal::SharedFunctionInfo::SearchOptimizedCodeMap
function foo() {
return [1, 2, 3];
}
function find(val){
function index (value) {
return foo().indexOf(value);
}
return index(val);
}
13.58% 58 | LazyCompile:*InnerArrayIndexOf native array.js:1020 9.82% 42 | Builtin:ArgumentsAdaptorTrampoline 7.49% 32 | LazyCompile:~index test1.js:6 7.01% 30 | LoadIC:A load IC from the snapshot * 6.08% 26 | Stub:FastNewClosureStub 5.62% 24 | Builtin:CallFunction_ReceiverIsNullOrUndefined 3.74% 16 | LazyCompile:*foo test1.js:1 3.51% 15 | Builtin:Call_ReceiverIsNullOrUndefined 3.51% 15 | LazyCompile:*indexOf native array.js:1065
В первом случае мы ходим много в среду исполнения и там занимаемся всякой тяжелой и малополезной работой (например, клонированием массива литералов привязанного к замыканию), а во втором случае мы быстренько создаем замыкание с помощью
FastNewClosureStub
. Вот отсюда и основная разница.Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Тонкости Javascript/Node.js. Увеличиваем производительность в десятки раз