При использовании узла, почему код намного быстрее с использованием "строгого использования"?

Я никогда не знал, use strict, чтобы ускорить время выполнения, однако простой use strict делает мой тест значительно быстрее, а медленный - намного медленнее (более чем в два раза медленнее). Что происходит?

//
// RUN WITH AND WITHOUT THIS
//
"use strict";

var assert = require('assert');

var slice = [].slice;

function thunkify_fast(fn){
  assert('function' == typeof fn, 'function required');

  return function(){
    var args = new Array(arguments.length);
    for(var i = 0; i < args.length; ++i) {
      args[i] = arguments[i];
    }
    var ctx = this;

    return function(done){
      var called;

      args.push(function(){
        if (called) return;
        called = true;
        done.apply(null, arguments);
      });

      try {
        fn.apply(ctx, args);
      } catch (err) {
        done(err);
      }
    }
  }
};

function thunkify_slow(fn){
  assert('function' == typeof fn, 'function required');

  return function(){
    var args = slice.call(arguments);
    var ctx = this;

    return function(done){
      var called;

      args.push(function(){
        if (called) return;
        called = true;
        done.apply(null, arguments);
      });

      try {
        fn.apply(ctx, args);
      } catch (err) {
        done(err);
      }
    }
  }
};


var fn = function () { };

var Benchmark = require('benchmark');
var suite = new Benchmark.Suite;


//
// Only one wrapper can be sent through the optimized compiler
//
suite.add( 'thunkify#fast', function () { thunkify_fast(fn)(function(){}) } )
    .add( 'thunkify#slow', function () { thunkify_slow(fn)(function(){}) } )
    .on('cycle', function(event) { console.log(String(event.target)); })
    .on('complete', function() {
        console.log('Fastest is ' + this.filter('fastest').pluck('name'));
    })
    .run();

Без этой вершины "use strict" результаты соответствуют этому,

$ node --allow-natives-syntax test.js 
thunkify#fast x 8,511,605 ops/sec ±1.22% (95 runs sampled)
thunkify#slow x 4,579,633 ops/sec ±0.68% (96 runs sampled)
Fastest is thunkify#fast

Однако, с этим "use strict;" я получаю это,

$ node --allow-natives-syntax test.js 
thunkify#fast x 9,372,375 ops/sec ±0.45% (100 runs sampled)
thunkify#slow x 1,483,664 ops/sec ±0.93% (96 runs sampled)
Fastest is thunkify#fast

Я использую nodejs v0.11.13. Это все часть работы, которую я выполняю, чтобы ускорить утяжеление узлов, используя это руководство. Интересно, что в руководстве по оптимизации Bluebird не упоминается use strict; о полезной производительности.

Больше возиться с этим, если я изменю контрольный пример на

var f_fast = thunkify_fast(fn);
var f_slow = thunkify_slow(fn);
suite.add( 'thunkify#fast', function () { f_fast(function(){}) } )
  .add( 'thunkify#slow', function () { f_slow(function(){}) } )
  .on('cycle', function(event) { console.log(String(event.target)); })
  .on('complete', function() {
    console.log('Fastest is ' + this.filter('fastest').pluck('name'));
  })
  .run();

тем самым удаляя вызовы thunkify Я все еще вижу то же самое. Случай использования use strict работает медленнее для неоптимизированного кода и быстрее для оптимизированного кода,

Нет строгого

thunkify#fast x 18,910,556 ops/sec ±0.61% (100 runs sampled)
thunkify#slow x 5,148,036 ops/sec ±0.40% (100 runs sampled)

"использовать строгое";

thunkify#fast x 19,485,652 ops/sec ±1.27% (99 runs sampled)
thunkify#slow x 1,608,235 ops/sec ±3.37% (93 runs sampled)

Ответы

Ответ 1

Причина этой медлительности заключается в этой проверке внутри встроенного ArraySlice. Он проверяет, пытаемся ли мы нарезать аргументы объекта, и если мы это делаем, то использует быстрый код для этого. Однако он проверяет только объект аргументов в неаккуратном режиме. Когда вы размещаете объект arguments внутри строгой функции, вы получаете объект аргументов строгого режима, сделанный из native_context()->strict_arguments_boilerplate(), что означает, что приведенная выше проверка не может его распознать и переходит к общему коду JavaScript, который медленнее, чем специализированный быстрый путь C++ с ручным кодированием. это займет для неаккуратного объекта аргументов.

Ответ 2

Ниже приводится цитата из статьи Mozilla о строгом режиме JavaScript

Гибкость JavaScript делает это практически невозможным без многих проверок во время выполнения. Некоторые функции языка так распространено, что выполнение проверок во время выполнения имеет значительную производительность Стоимость. Несколько строгих настроек режима, плюс требование, чтобы пользователь отправлял JavaScript должен быть строгим режимом кода и чтобы он вызывался в определенном таким образом, существенно сократить потребность в этих проверках во время выполнения.

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

Как вы знаете, строгий режим отключает несколько функций, которые JavaScript предоставил ранее (большинство из них считается плохой практикой). Поскольку браузер может легко выдавать ошибки при использовании строгого режима, он не должен выполнять проверки и принимать за вас исправления кода. Таким образом, приводит к улучшению производительности.

Ответ 3

Просто хотел добавить к четанскому ответу. Я укажу вам на вопрос, который вы задали совсем недавно. Скорее всего, это ответ.

Строгий режим делает определенные предположения о вашем коде и добавляет дополнительные проверки. Эти проверки имеют два эффекта, связанных с производительностью (по сравнению с обычным режимом):

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

Производительность улучшится в строгом режиме, пока 2 перевешивает 1. Это работает, как и ожидалось для вашей первой функции. Для вашей второй функции никакие оптимизации не могут быть сделаны !! Компилятор выручает, когда видит небезопасное использование аргументов. Таким образом, первый эффект - это все, что осталось.

Я полагаю, что неоптимизируемый код требует гораздо больше штрафов в строгом коде. Дополнительные проверки ничего не дают.