Нужно ли современному JITER JavaScript кэширование по длине массива в циклах? - PullRequest
13 голосов
/ 07 июня 2011

Я считаю, что практика кэширования свойства length массива внутри цикла for весьма неприятна.Например,

for (var i = 0, l = myArray.length; i < l; ++i) {
    // ...
}

По крайней мере, на мой взгляд, это сильно ухудшает читабельность по сравнению с простым

for (var i = 0; i < myArray.length; ++i) {
    // ...
}

(не говоря уже о том, что из-за утечки в окружающую функцию вытекает другая переменная)к природе лексического охвата и подъема.)

Я хотел бы быть в состоянии сказать любому, кто делает это, "не беспокойтесь; современные JS JITers оптимизируют этот трюк".Очевидно, что это не тривиальная оптимизация, так как вы можете, например, изменить массив во время его итерации, но я думаю, учитывая все сумасшедшие вещи, которые я слышал о JITers и их приемах анализа времени выполнения, они могли бы получить этосейчас.

У кого-нибудь есть доказательства, так или иначе?

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

Ответы [ 3 ]

12 голосов
/ 07 июня 2011

Это зависит от нескольких вещей:

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

Из тестов, которые я видел (например, здесь и здесь ), видно, что производительность в IE <9 (как правило, будет самым медленным браузером, с которым вам придется иметь дело) with) выигрывает от кэширования длины массива, так что это может стоить сделать. Что бы это ни стоило, у меня есть давняя привычка кэшировать длину массива, и в результате мне легко читать. Существуют также другие оптимизации цикла, которые могут иметь эффект, например, обратный отсчет, а не увеличение. </p>

Вот соответствующая дискуссия по этому вопросу из списка рассылки JSMentors: http://groups.google.com/group/jsmentors/browse_thread/thread/526c1ddeccfe90f0

5 голосов
/ 07 июня 2011

Мои тесты показывают, что все основные новые браузеры кешируют свойство length массивов. Вам не нужно кэшировать его самостоятельно, если вы не озабочены IE6 или 7, я точно не помню. Однако с тех пор я использую другой стиль итерации, поскольку он дает мне еще одно преимущество, которое я опишу в следующем примере:

var arr = ["Hello", "there", "sup"];
for (var i=0, str; str = arr[i]; i++) {
  // I already have the item being iterated in the loop as 'str'
  alert(str);
}

Вы должны понимать, что этот стиль итерации прекращается, если массиву разрешено содержать значения 'falsy', поэтому этот стиль нельзя использовать в этом случае.

3 голосов
/ 26 сентября 2012

Прежде всего, как это труднее сделать или менее разборчиво?

var i = someArray.length;
while(i--){
    //doStuff to someArray[i]
}

Это не какая-то странная загадочная микрооптимизация. Это просто основной принцип уклонения от работы. Не используя «.» или операторы «[]», более чем необходимые, должны быть такими же очевидными, как не пересчитывать число «Пи» более одного раза (при условии, что вы не знали, что у нас это уже есть в объекте Math).

[вычурные элементы]

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

Но это требует изрядного количества сложности. Каждый раз, когда вы делаете что-либо, изменяющее массив, вы должны обрабатывать длину как статическое свойство и указывать вашим методам изменения массива (я имею в виду ту часть кода, которую я имею в виду) установить свойство вручную, тогда как обычно длина просто подсчитывает элементы каждый раз, когда это происходит. ссылки. Это означает, что каждый раз, когда добавляется новый метод изменения массива, вы должны обновлять JIT для поведения ветвления для ссылок длины массива с локальной областью действия.

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

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

Кэширование поиска свойств и возврата методов выполняется легко, очищает ваш код и в конечном итоге делает его более гибким и надежным в плане производительности перед лицом изменений. Даже если один или два JIT сделали это ненужным в обстоятельствах, включающих несколько «если», вы не могли быть уверены, что они всегда будут, или что ваш код будет продолжать делать это возможным.

Так что да, извиняюсь за рассылку о запрете использования компилятора-дескриптора, но я не понимаю, почему вы захотите не кэшировать свои свойства. Это просто. Чисто. Это гарантирует лучшую производительность независимо от браузера или перемещения объекта, свойства которого проверены во внешней области.

Но меня действительно бесит, что документы Word теперь загружаются так же медленно, как они это делали в 1995 году, и что люди продолжают писать ужасно медленно работающие веб-сайты на Java, хотя виртуальная машина Java якобы превосходит всех не скомпилированных претендентов по производительности. Я думаю, что это представление о том, что вы можете позволить компилятору разобраться в деталях производительности, и что «современные компьютеры настолько быстры», во многом связано с этим. Мы всегда должны помнить об уклонении от работы, когда работы легко избежать и не угрожает удобочитаемости / ремонтопригодности, ИМО. Работа по-другому никогда не помогла мне (или я подозреваю кого-либо) написать код быстрее в долгосрочной перспективе.

...