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.