Производительность присвоения значений массиву

Оптимизация кода здесь, в SO, говорит о том, что профилирование является первым шагом для оптимизации javascript, а предлагаемые движки - это профилировщики Chrome и Firefox. Проблема с ними в том, что они странным образом сообщают время выполнения каждой функции, но я не очень хорошо их понимаю. Наиболее полезным способом было бы, чтобы профилировщик сообщал, сколько раз выполняется каждая строка и, если возможно, также время, которое затрачивается на каждую строку. Таким образом можно было бы строго увидеть узкие места. Но прежде чем такой инструмент будет реализован / найден, у нас есть два варианта:

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

Для варианта 2jsperf.com очень помогает Я попытался изучить оптимизирующие массивы и сделал тест скорости вJSPERF.COM, На следующем рисунке показаны результаты в 5 основных браузерах и обнаружены некоторые узкие места, о которых я раньше не знал.

Основные выводы были:

1) Назначение значений массивам значительно медленнее, чем назначение нормальным переменным, несмотря на то, какой метод используется для назначения.

2) Предварительная инициализация и / или предварительное заполнение массива до того, как критические циклы производительности могут значительно улучшить скорость

3) Математические тригонометрические функции не такие медленные по сравнению с переносом значений в массивы (!)

Вот объяснения каждого теста:

1. non_array (100%):

Переменным было присвоено заранее определенное значение следующим образом:

var non_array_0=0;
var non_array_1=0;
var non_array_2=0;
...

и во временной области они назывались так:

non_array_0=0;
non_array_1=1;
non_array_2=2;
non_array_3=3;
non_array_4=4;
non_array_5=5;
non_array_6=6;
non_array_7=7;
non_array_8=8;
non_array_9=9;

Выше приведена переменная, похожая на массив, но, похоже, нет способа итерировать или ссылаться на эти переменные иначе, чем на массив. Или есть?

Ничто в этом тесте не быстрее, чем присвоение номера переменной.

2. non_array_non_pre (83,78%)

Точно так же, как тест 1, но переменные не были предварительно инициализированы или предварительно заполнены. Скорость составляет 83,78% от скорости теста 1. В каждом протестированном браузере скорость предварительно заполненных переменных была выше, чем без предварительно заполненных.Поэтому инициализируйте (и, возможно, предварительно заполняйте) переменные вне любых циклов, критичных к скорости.

Тестовый код здесь:

var non_array_non_pre_0=0;
var non_array_non_pre_1=0;
var non_array_non_pre_2=0;
var non_array_non_pre_3=0;
var non_array_non_pre_4=0;
var non_array_non_pre_5=0;
var non_array_non_pre_6=0;
var non_array_non_pre_7=0;
var non_array_non_pre_8=0;
var non_array_non_pre_9=0;

3. pre_filled_array (19,96%):

Массивы злые! Когда мы отбрасываем нормальные переменные (test1 и test2) и помещаем массивы в изображение, скорость значительно уменьшается.Хотя мы выполняем все оптимизации (предварительно инициализируем и предварительно заполняем массивы), а затем присваиваем значения напрямую, без зацикливания или нажатия, скорость снижается до 19,96 процента. Это очень грустно, и я действительно не понимаю, почему это происходит. Это был один из главных шоков для меня в этом тесте. Массивы так важны, и я не нашел способа сделать многие вещи без массивов.

Тестовые данные здесь:

pre_filled_array[0]=0;
pre_filled_array[1]=1;
pre_filled_array[2]=2;
pre_filled_array[3]=3;
pre_filled_array[4]=4;
pre_filled_array[5]=5;
pre_filled_array[6]=6;
pre_filled_array[7]=7;
pre_filled_array[8]=8;
pre_filled_array[9]=9;

4. non_pre_filled_array (8,34%):

Это тот же тест, что и в 3, но члены массива не инициализируются и не заполняются предварительно, только оптимизация заключалась в предварительной инициализации массива:var non_pre_filled_array=[];

Скорость снижается на 58,23% по сравнению с преинициализированным тестом 3.Таким образом, предварительная инициализация и / или предварительное заполнение массива удваивают скорость.

Тестовый код здесь:

non_pre_filled_array[0]=0;
non_pre_filled_array[1]=1;
non_pre_filled_array[2]=2;
non_pre_filled_array[3]=3;
non_pre_filled_array[4]=4;
non_pre_filled_array[5]=5;
non_pre_filled_array[6]=6;
non_pre_filled_array[7]=7;
non_pre_filled_array[8]=8;
non_pre_filled_array[9]=9;

5. pre_filled_array [i] (7,10%):

Тогда к петлям. Самый быстрый метод зацикливания в этом тесте. Массив был предварительно инициализирован и предварительно заполнен.

Падение скорости по сравнению со встроенной версией (тест 3) составляет 64,44%. Это настолько замечательная разница, что я бы сказал, не зацикливаться, если не нужно. Если размер массива небольшой (не знаю, насколько он маленький, его нужно тестировать отдельно), лучше использовать встроенные назначения вместо циклических.

И поскольку падение скорости настолько велико, и нам действительно нужны петли, разумно найтилучший метод зацикливания (например.while(i--)).

Тестовый код здесь:

for(var i=0;i<10;i++)
{
  pre_filled_array[i]=i;
}

6. non_pre_filled_array [i] (5,26%):

Если мы не преинициализируем и не заполняем массив, скорость уменьшается на 25,96%. Опять же, разумна предварительная инициализация и / или предварительное заполнение перед циклом, критическим для скорости.

Код здесь:

for(var i=0;i<10;i++) 
{
  non_pre_filled_array[i]=i;
}

7. Математические расчеты (1,17%):

Каждый тест должен быть ориентиром. Математические функции считаются медленными. Тест состоял из десяти «тяжелых» математических вычислений, но теперь пришло другое, что поразило меня в этом тесте. Посмотрите на скорость 8 и 9, где мы помещаем десять целых чисел в массив в цикле. Вычисление этих 10 математических функций более чем на 30% быстрее, чем вставка десяти целых чисел в массив в цикле. Так что, может быть, легче преобразовать некоторые толчки массива в предварительно инициализированные не-массивы и сохранить эти тригонометрии. Конечно, если в кадре сотни или тысячи вычислений, целесообразно использовать, например. sqrt вместо sin / cos / tan и использовать расстояния такси для сравнения расстояний иУглы ромба (t-радианы) для сравнения углов, но все же основное узкое место может быть в другом месте: цикл медленнее, чем встраивание, нажатие медленнее, чем при использовании прямого назначения с предварительной инициализацией и / или предварительным заполнением, логика кода, алгоритмы рисования и доступ к DOM могут быть медленными. Все не может быть оптимизировано в Javascript (мы должны что-то видеть на экране!), Но все, что мы можем сделать легко и важно, это разумно. Кто-то здесь, в SO, сказал, что код предназначен для людей, и читаемый код важнее, чем быстрый код, потому что затраты на обслуживание являются самыми большими. Это экономичная точка зрения, но я обнаружил, что оптимизация кода может обеспечить и элегантность, и удобочитаемость, и производительность. И если достигается повышение производительности на 5%, а код становится более понятным, это дает хорошее чувство!

Код здесь:

non_array_0=Math.sqrt(10435.4557);
non_array_1=Math.atan2(12345,24869);
non_array_2=Math.sin(35.345262356547);
non_array_3=Math.cos(232.43575432);
non_array_4=Math.tan(325);
non_array_5=Math.asin(3459.35498534536);
non_array_6=Math.acos(3452.35);
non_array_7=Math.atan(34.346);
non_array_8=Math.pow(234,222);
non_array_9=9374.34524/342734.255;

8. pre_filled_array.push (i) (0,8%):

Толчок это зло! Толчок к петле - это губительное зло! По какой-то причине это очень медленный способ присвоения значений массиву. Тест 5 (прямые присваивания в цикле) выполняется почти в 9 раз быстрее, чем этот метод, и оба метода делают одно и то же: присваивают целое число 0-9 в предварительно инициализированный и предварительно заполненный массив. Я не проверял, является ли эта злобность «нажми за петлю» следствием толкания или зацикливания или комбинации обоих или количества зацикливаний. В JSPERF.COM есть другие примеры, которые дают противоречивые результаты. Разумнее проверять только реальные данные и принимать решения. Этот тест может быть несовместим с другими данными, чем те, которые были использованы.

И вот код:

for(var i=0;i<10;i++)
{
  pre_filled_array.push(i);
}

9. non_pre_filled_array.push (i) (0,74%):

Последний и самый медленный метод в этом тесте такой же, как тест 8, но массив не заполняется заранее. Немного медленнее, чем 9, но разница не значительна (7,23%). Но давайте возьмем пример и сравним этот самый медленный метод с самым быстрым.Скорость этого метода составляет 0,74% от скорости метода 1, что означает, что метод 1 в 135 раз быстрее, чем этот. Поэтому тщательно продумайте, нужны ли массивы в конкретном случае использования. Если это только один или несколько нажатий, общая разница в скорости не заметна, но, с другой стороны, если имеется только несколько нажатий, они очень просты и элегантны для преобразования в переменные, не являющиеся массивами.

Это код:

for(var i=0;i<10;i++)
{
  non_pre_filled_array.push(i);
}

И, наконец, обязательный вопрос:

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

Я не могу использоватьvar variable_$i = 1 в цикле, так что $ я конвертируется в некоторое целое число. Я должен использоватьvar variable[i] = 1 что значительно медленнее, чемvar variable1 = 1 как показал тест. Это может быть критично только тогда, когда есть большие массивы и во многих случаях они есть.

РЕДАКТИРОВАТЬ: я сделал новый тест, чтобы подтвердить медлительность доступа к массивам и попытался найти более быстрый путь:

http://jsperf.com/read-write-array-vs-variable

Array-read и / или array-write значительно медленнее, чем обычные переменные. Если некоторые операции выполняются с элементами массива, разумнее сохранить значение элемента массива во временной переменной, выполнить эти операции для временной переменной и, наконец, сохранить значение в элементе массива. И хотя код становится больше, эти операции выполняются значительно быстрее, чем в цикле.

Заключение: массивы и обычные переменные аналогичны диску и памяти. Обычно доступ к памяти быстрее, чем к диску, а обычный доступ к переменным быстрее, чем к массиву. И, может быть, конкатенация операций также быстрее, чем использование промежуточных переменных, но это делает код немного не читаемым.

Ответы на вопрос(1)

Ваш ответ на вопрос