Post increment vs pre increment - Оптимизация Javascript
Я просматривал Google Code, когда я оценил этот проект под названием JSpeed - оптимизация для Javascript.
Я заметил, что одна из оптимизаций заключалась в изменении i++
на ++i
для операторов цикла.
Перед оптимизацией
for (i=0;i<1;i++) {}
for (var i = 0, j = 0; i < 1000000; i++, j++) {
if (i == 4) {
var tmp = i / 2;
}
if ((i % 2) == 0) {
var tmp = i / 2;
i++;
}
}
var arr = new Array(1000000);
for (i = 0; i < arr.length; i++) {}
После оптимизации
for(var i=0;i<1;++i){}
for(var i=0,j=0;i<1000000;++i,++j){if(i==4){var tmp=i>>1;}
if((i&1)==0){var tmp=i>>1;i++;}}
var arr=new Array(1000000);for(var i=0,arr_len=arr.length;i<arr_len;++i){}
Я знаю, что делают pre и post increments, но любая идея, как это ускоряет код?
Ответы
Ответ 1
Это то, что я прочитал и могу ответить на ваш вопрос: "preincrement (++i
) добавляет значение к значению i
, а затем возвращает i
; напротив, i++
возвращает i
, затем добавляет один к нему, что теоретически приводит к созданию временной переменной, сохраняющей значение i
до того, как была применена операция приращения".
Ответ 2
Это искусственная оптимизация. Насколько я понимаю, вы сохраняете 1 op-код. Если вы хотите оптимизировать свой код с помощью этой техники, то вы пошли не так. Кроме того, большинство компиляторов/переводчиков в любом случае оптимизируют это для вас (ссылка 1). Короче, я бы не волновался. Но, если вы действительно волнуетесь, вы должны использовать i+=1
.
Вот быстрый и грязный бенчмарк, который я только что сделал
var MAX = 1000000, t=0,i=0;
t = (new Date()).getTime();
for ( i=0; i<MAX;i++ ) {}
t = (new Date()).getTime() - t;
console.log(t);
t = (new Date()).getTime();
for ( i=0; i<MAX;++i ) {}
t = (new Date()).getTime() - t;
console.log(t);
t = (new Date()).getTime();
for ( i=0; i<MAX;i+=1 ) {}
t = (new Date()).getTime() - t;
console.log(t);
Исходные результаты
Post Pre +=
1071 1073 1060
1065 1048 1051
1070 1065 1060
1090 1070 1060
1070 1063 1068
1066 1060 1064
1053 1063 1054
Удалены самые низкие и самые высокие
Post Pre +=
1071 ---- 1060
1065 ---- ----
1070 1065 1060
---- 1070 1060
1070 1063 ----
1066 1060 1064
---- 1063 1054
Средние
1068.4 1064.2 1059.6
Обратите внимание, что это более миллион итераций, и результаты в среднем равны 9 миллисекундам. Не очень большая оптимизация, учитывая, что большая итеративная обработка в JavaScript выполняется на гораздо меньших наборах (например, контейнеры DOM).
Ответ 3
Звучит как преждевременная оптимизация. Когда вы почти закончили свое приложение, проверьте, где находятся узкие места, и оптимизируйте их по мере необходимости. Но если вы хотите получить подробное руководство по производительности контура, проверьте это:
http://blogs.oracle.com/greimer/entry/best_way_to_code_a
Но вы никогда не знаете, когда это станет устаревшим из-за усовершенствований движка JS и изменений между браузерами. Лучший выбор - не беспокоиться об этом, пока это не проблема. Сделайте свой код понятным для чтения.
Изменить: согласно этот парень, pre-vs. post статистически незначителен. (возможно, даже хуже)
Ответ 4
Оптимизация не является префиксом по сравнению с post increment. Это использование побитовых операторов "shift" и "and", а не разделение и мода.
Существует также оптимизация минимизации javascript для уменьшения общего размера (но это не оптимизация времени исполнения).
Ответ 5
Тест Anatoliy включал пост-инкремент внутри тестовой функции pre-increment: (
Вот результаты без этого побочного эффекта...
function test_post() {
console.time('postIncrement');
var i = 1000000, x = 0;
do x++; while(i--);
console.timeEnd('postIncrement');
}
function test_pre() {
console.time('preIncrement');
var i = 1000000, x = 0;
do ++x; while(--i);
console.timeEnd('preIncrement');
}
test_post();
test_pre();
test_post();
test_pre();
test_post();
test_pre();
test_post();
test_pre();
Выход
postIncrement: 3.21ms
preIncrement: 2.4ms
postIncrement: 3.03ms
preIncrement: 2.3ms
postIncrement: 2.53ms
preIncrement: 1.93ms
postIncrement: 2.54ms
preIncrement: 1.9ms
Это большая разница.
Ответ 6
Просто протестировал его в firebug и не нашел разницы между post- и preincrements. Может быть, эта оптимизация других платформ?
Вот мой код для тестирования firebug:
function test_post() {
console.time('postIncrement');
var i = 1000000, x = 0;
do x++; while(i--);
console.timeEnd('postIncrement');
}
function test_pre() {
console.time('preIncrement');
var i = 1000000, x = 0;
do ++x; while(i--);
console.timeEnd('preIncrement');
}
test_post();
test_pre();
test_post();
test_pre();
test_post();
test_pre();
test_post();
test_pre();
Выход:
postIncrement: 140ms
preIncrement: 160ms
postIncrement: 136ms
preIncrement: 157ms
postIncrement: 148ms
preIncrement: 137ms
postIncrement: 136ms
preIncrement: 148ms
Ответ 7
Это, вероятно, грузо-культовое программирование.
Это не должно иметь значения, если вы используете достойные компиляторы/интерпретаторы для языков, которые не имеют произвольной перегрузки оператора.
Эта оптимизация имела смысл для С++, где
T x = ...;
++x
может изменить значение на месте, тогда как
T x = ...;
x++
необходимо создать копию, выполнив что-то под капотом, например
T x = ...;
T copy;
(copy = T(x), ++x, copy)
что может быть дорогостоящим для больших типов структур или для типов, которые выполняют множество вычислений в своем конструкторе `copy.