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

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

Что-то в это

// обычный цикл
for(var i=0; i<items.length; i++) {
  // код здесь...
}

// такой цикл работает быстрее
var size = items.length;
for(var i=0;i<size; i++){
  // код здесь...
}


слабо верится. И JSPerf — не аргумент.

Вся остальная статья предельно логична. Другого и не ожидалось. Rivertrail по идее ожидается в ES7 или ES8, т.е. году в 2016 примерно. И то, не понятно, что с ним будет теперь, когда Брендан — основной пропагандист SIMD в JS — ушел из Mozilla.
это будет так если не оптимизирован доступ к .length для цикла.
Отличная статья, спасибо.
А что аргумент, в таком случае?
Аргумент может звучать только так:

«Мы профилировали наше приложение и после N запусков профайлера и выполнения одного и того же сценария получили следующие данные о времени выполнения. Мы оптимизировали самые проблемные кучки и после повторных серий замеров производительности получили такой-то прирост. В частности, для нашего сценария вынесение вычисления длинны массива за цикл принесло на X% меньшее выполнение программы.»


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

В сочетании с тем, что большинство разработчиков JS-движков считают 99% бенчмарков на JSPerf невалидными, я склонен подвергать сомнению вывод, содержащийся в статье. Если бы вместо ссылки на JSPerf были ссылки на результаты запуска профайлера для pics.io до и после, я бы согласился.
В данном конкретном случае это не так. items нельзя соптимизировать, items может меняться. JS — это такой язык, что получение значение i может привести к изменению длины items. JIT старается оптимизировать то что точно даст на выходе тот же результат, но это не про циклы.
items нельзя соптимизировать


можно

JS — это такой язык, что получение значение i может привести к изменению длины items.


typeof i = "number"


Нет такого метода, хука или чего-то такого, что может вызвать какой-то код при обращении к значению числа. Против смены длины, также как против смены значения/типа JIT ставит гард в SSA-код. Так что оптимизировать доступ к полю, превратить его в константу и вынести инвариант за границы цикла можно. V8, SpiderMonkey, JSC и Chakra это делают.
Вариант 1. items.length — геттер
Вариант 2. items.length — объект с valueOf
Вариант 3. Это js, давно нам JIT запретил поменять сам Number.prototype.valueOf? (про i)

Чисто логически это два разных кода — в одном мы говорим что нам надо проиттерироваться до 10, а в другом что до длины массива, получаемой на каждом шагу. Может быть случай когда надо действительно делать это до начальной размерности массива, хотя он при этом растёт. Лично получал полтора года назад эффект от вынесение получение длины за сравнение, но там был двумерный массив и вложенность циклом достигала трёх.
также как против смены значения/типа JIT ставит гард в SSA-код

Где можно посмотреть/почитать об этом?
слабо верится. И JSPerf — не аргумент.

Я вас не обманываю!
// такой цикл работает быстрее
var size = items.length;
for(var i=0;i<size; i++){
  // код здесь...
}

можно записать чуть компактнее, хотя смысл не меняется:

for(var i=0, size = items.length; i<size; i++){
  // код здесь...
}
слабо верится

Это же классика для многих языков: в первом варианте размер повторно вычисляется при каждой итерации, во втором примере размер заранее известен.
При современных реалиях правда разница будет ощутима при действительно больших массивах данных.
«При современных реалиях» многие компиляторы сами делают эту оптимизацию.
Ога. И именно по этому во многих языках в тестах 2–ой вариант оказывается быстрее.
Не поэтому, очевидно.
К чему тогда
многие компиляторы сами делают эту оптимизацию.
?
Если компилятор сам делает эту оптимизацию, то производительность обоих вариантов в тестах будет идентичной.
особо умные компиляторы ещё будут делать проверку на выход индекса из диапазона, а ещё более умные-умные не будут делать её для i < items.length, так как там выйти из диапазона нельзя. тогда 2-й окажется быстрее. но, в JS я бы не надеялся.
«В современных» — это каких? Даже в PHP, где до сих пор нет нормальной поддержки юникода (да, я знаю про mbstring), это и то оптимизировано давно. А уж в остальных языках и подавно. Высчитывать длину *массива* каждый раз — это ппц. Не знаю что надо выкурить разработчику языка, чтобы это не кешировать.

Конкретно тут, скорее всего, оптимизация есть за счет уменьшения времени доступа. К локальной переменной быстрее, чем к свойству. Учитывая фразу «обрабатываем массивы по 20000000+ элементов», может быть актуально.
«В современных» — это каких?

Это относилось к реалиям (подразумевалось производительность современных РС), а не к языкам.

Даже в PHP, где до сих пор нет нормальной поддержки юникода (да, я знаю про mbstring), это и то оптимизировано давно.

Тесты упрямо не хотят это доказывать. Разница по производительности ~8 раз в пользу последнего.
Эх, пока не будет инструментов для редактирования, смысла большого в этом сервисе нет. Вшитая в равку jpg превьюшка выглядит лучше, чем проявленный без профилей камеры raw.
При редкатировании, кстати, можно проявлять не всю равку целиком (для превью), а уменьшенный вариант, как это и делают рав конверторы.
Как разные конверторы уменьшают raw?
Расскажите, мы как раз думаем над похожим подходом!
Посмотрите, например на dcraw, баловался с ним, когда хотел сделать похожий сервис, но с обработкой на стороне сервера. Там можно проявлять не целиком, а в половину размера (или в четверть), что соотвественно быстрее и как раз годится для превью во время редактирования. А при финальном сохранении уже работать с полноразмерным изображением. Так же поступают и «большие» конверторы, типа лайтрума.
Профили камер бы еще в идеале добавить, их можно взять из открытых проектов, типа darktable.
Взяли из darktable + из rawspeed + сами нагенерировали!
Да, конечно. Я поинтересовался, потому что подумал, что вы знаете как это происходит! Просто выбрасываются какие-то строки/столбцы? Или какой-то более грамотный ресемплинг?

dcraw можно посмотреть в код, а Lightroom?
Нет, к сожалению, до исходников руки не дошли, другие задачи были.
У лайтрума во что то там внутреннее конвертируется, посмотреть, например, на их smartpreview.
Smart Preview у Lightroom — это DNG уменьшенный в несколько раз и пожатый с потерей качества.
В прошлый раз вас хвалил, и сейчас похвалю, действительно стало ещё быстрее. Насчёт в 3 раза, не заметил, но процентов на 50 точно.
Тестовый DNG (26 Мб, 22 Мпикс) — ~3 секунды загрузка, ~5 секунд обработка
Тестовый CR2 (30 Мб, 22 Мпикс) — ~3 секунды загрузка, ~7 секунд обработка
По-моему вполне приличные цифры для онлайн-инструмента
Да про скорость я вообще то ничего не сказал. Учитывая то, что проявка raw это достаточно ресурсоемкая задача, проявка на JavaScript за 7 секунд это очень и очень хороший результат.
Но сама по себе проявка без редактирования не нужна, проще вытащить вшитую jpg и получить по дефолту лучшую картинку, да и если на то пошло дело, конвертировать можно и в самом фотоаппарате, даже с какими то минимальными настройками.
И как только дело дойдет до настроек (банально баланс белого и пр.), то тут то и начнутся затыки — при изменении настроек, хочется видеть результат быстро а не ждать по 5-7 секунд. Я и посоветовал приглядеться к проявке не полного файла.
Согласен, но как я понял, это только ранняя стадия разработки. Насчёт проявки неполного файла, интересное решение сделали в Lightroom mobile, когда работа ведётся в рамках Smart Preview, а потом синхронизируется с десктопом.
SmartPreview кроме как на ipad удобно использовать при переносе на другой компьютер: создал каталог, перенес на флешке или через облако на другое рабочее место и правь на здоровье ) В lightroom mobile достаточно скудные возможности проявки (
Будем ещё быстрее!
Не во всех камерах есть полноразмерные превью. А в некоторых их вообще нет.
Как разные конверторы уменьшают raw?
Расскажите, мы как раз думаем над похожим подходом!
Реализации JavaScript движков разнятся от браузера к браузеру и один и тот же код работает по-разному в Chrome и FF.
Если у кого-то есть мысли на этот счет, пожалуйста, прокомментируйте.


Три года назад занимался оптимизацией кроссбраузерной монструозной страницы (100 000 ДОМ-элементов).

Разница была заметна по-большей части в работе с добавлением нод в ДОМ:
  • innerHTML = в Chrome начинал безбожно тупить с ростом количества нод — пришлось делать вставку чанками.
  • innerHTML = одного большого куска HTML в IE6,7 оказался быстрее всех остальных способов
  • documentFragment в Firefox оказался быстрее всех остальных способов


К тому же [].join('') для конкатенации строк быстрее в IE, а Chrome и Firefox оптимизируют str += str.

mikenerevarin может рассказать про прочие хардкорные оптимизации.
У ребят узкое место — явно не DOM, а работа с бинарными данными. Поэтому для них важен параллелизм данных, типизированные хранилища и упрощение структур данных для снижения нагрузки на GC.

Это не отменяет полезности вашего комментария.
НЛО прилетело и опубликовало эту надпись здесь
Да, вы правы. Именно для этого я уточнил, что эти вещи были актуальны три года назад.
// такой цикл работает быстрее
var size = items.length;
for(var i=0;i<size; i++){
  // код здесь...
}


Попробуйте так:
for(var i=items.length;i--;){
  // код здесь...
}


Но если важен порядок обработки — придется сортировку у массивов менять (поскольку i итерируется не вверх, а вниз). На моём компе при суммировании 300 тысяч элементов первый вариант выдаёт 18-20мс, второй — 16-18мс.
Где могли так и сделали!
Подскажите, пожалуйста, за отсутствием каких возможностей IE11 переадресовывается на raw.pics.io/ancient?
Спасибо! =)
Мы не успеваем протестировать в IE11, Opera и некоторых других браузерах. Возможно. всё будет OK, а возможно нет.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий