Javascript var vs let (de) проблема оптимизации / замедления в v8 и SpiderMonkey

Во время рефакторинга кода JavaScript в моем проекте я обнаружил, что некоторые из моих циклов резко замедлились. Поиск основной причины Я нашел этот вопрос о том, что замедление вызвано let заявление внутри for создание цикла и замыкания. К моему удивлению, переезд let и закрытие из for петля не помогла, и даже с помощью var вместо let переменная цикла также не помогает, потому что замедление вызвано let размещены после for петля. Удалив дополнительные детали, я получил этот фрагмент кода:

"use strict"
console.log("=========================");
(function(){
    var itr = 0;
    function f(){++itr;}
    console.time('without_let');
    for(var i = 0; i < 50000000; ++i){
        f();
    }
    var totals = 0;
    console.timeEnd('without_let'); //chrome: 122ms, FF:102ms
})();

(function(){
    var itr = 0;
    function f(){++itr;}
    console.time('let_below');
    for(var i = 0; i < 50000000; ++i){
        f();
    }
    let totals = 0; // <--- notice let instead of var
    console.timeEnd('let_below'); //chrome: 411ms, FF:99ms
})();

(function(){
    let itr = 0;
    function f(){++itr;}
    console.time('let_above_and_in_loop');
    for(let i = 0; i < 50000000; ++i){
        f();
    }
    var totals = 0;
    console.timeEnd('let_above_and_in_loop'); //chrome: 153ms, FF:899ms
})();

(function(){
    var itr = 0;
    function f(){++itr;}
    console.time('let_in_loop');
    for(let i = 0; i < 50000000; ++i){
        f();
    }
    var totals = 0;
  console.timeEnd('let_in_loop'); //chrome: 137ms, FF:102ms
})();

(также на JS Fiddle Примечание: использование JS Fiddle показывает немного разные результаты, но аналогичное замедление все еще присутствует в тех же местах)

Запуск этого на Chrome производит следующее

 without_let: 122ms
 let_below: 411ms <----------- Slowdown for v8
 let_above_and_in_loop: 153ms
 let_in_loop: 137ms

Некоторый поиск в Google привел меня к статье о том, что let вызвал деоптимизацию до Chrome 56 / V8 5.6! но у меня chrome 57.0.2987.133 (64-битный) и v8 ver 5.7.492.71. Больше сюрпризов при попытке запустить это на Firefox 52.0.2 (32-разрядная версия). Здесь мы имеем замедление в другом месте, когда переменная создана с let используется внутри закрытия:

 without_let: 101.9ms
 let_below: 99ms
 let_above_and_in_loop: 899ms <----- Slowdown for SpiderMonkey
 let_in_loop: 102ms

Как я вижу, проблема в некоторой степени связана с так называемой функцией "временной мертвой зоны", но все еще неясна:

  1. Почему два основных браузера (основные движки JavaScript) по-прежнему не могут оптимизировать эти (разные) части фрагмента?

  2. Есть ли обходные пути, чтобы продолжать использовать let (кроме использования Babel, чтобы превратить let в var)? Предположим, я могу передать параметры в Chrome или даже напрямую в V8 через v8::V8::SetFlagsFromCommandLine(&argc, argv, true);

UPD: в Chrome ver 58.0.3029.96 соответствующая версия v8 5.8.283.37 (согласно https://omahaproxy.appspot.com/) после включения chrome://flags/#enable-v8-future, как предложено ниже в jmrk, все еще существует замедление для третьего случая (теперь 2 раза вместо 8 раз)

without_let: 157.000ms
let_below: 155.000ms
let_above_and_in_loop: 304.000ms
let_in_loop: 201.000ms

Firefox 53.0 (32 бита)

without_let: 278.650ms
let_below: 310.290ms
let_above_and_in_loop: 848.325ms
let_in_loop: 275.495ms

1 ответ

Я могу ответить на V8 часть вопроса. Замедление, которое вы видите, связано с ограничением старого оптимизирующего компилятора (известного как "Коленчатый вал"). За все это время эта проблема не рассматривалась, потому что команда была занята работой над новым оптимизирующим компилятором ("Turbofan"), который поставляется в Chrome 59 (в настоящее время на каналах Canary и Dev, скоро в бета-версии!).

В Chrome 58 (в настоящее время в бета-версии) вы уже можете получить предварительный просмотр, установив для "Экспериментального конвейера компиляции JavaScript" значение "Включено" (в chrome://flags/#enable-v8-future). Обратите внимание, что Chrome 59 будет иметь несколько дополнительных улучшений производительности.

Примечание: в существующей кодовой базе нет особого преимущества при переходе на letтак что вы можете просто продолжать использовать var,

Другие вопросы по тегам