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
Как я вижу, проблема в некоторой степени связана с так называемой функцией "временной мертвой зоны", но все еще неясна:
Почему два основных браузера (основные движки JavaScript) по-прежнему не могут оптимизировать эти (разные) части фрагмента?
Есть ли обходные пути, чтобы продолжать использовать
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
,