使用节点,为什么代码使用"use strict"更快?

Eva*_*oll 19 optimization v8 strict node.js

我从来不知道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();
Run Code Online (Sandbox Code Playgroud)

没有那个顶部"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
Run Code Online (Sandbox Code Playgroud)

然而,有了这个"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
Run Code Online (Sandbox Code Playgroud)

我正在运行nodejs v0.11.13.这是我正在使用本指南加速节点thunkify的工作的一部分.有趣的是,蓝鸟优化指南没有提到它的有益表现.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();
Run Code Online (Sandbox Code Playgroud)

从而删除调用thunkify我仍然看到相同的事情..使用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)
Run Code Online (Sandbox Code Playgroud)

"使用严格;"

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)
Run Code Online (Sandbox Code Playgroud)

Vya*_*rov 14

这种缓慢的原因是在ArraySlice内置的这个检查中.它测试我们是否尝试切片参数对象,如果我们这样做,那么使用快速代码来做.但是它只检查sloppy模式参数对象.当您在strict函数内部分配参数对象时,您将获得严格模式参数对象,native_context()->strict_arguments_boilerplate()这意味着上面的检查无法识别它并落入通用JavaScript代码,该代码比专用的手动编码C++快速路径慢.邋arguments的论点对象.


Che*_*sin 11

以下是Mozilla关于JavaScript严格模式的文章的引用

JavaScript的灵活性使得在没有许多运行时检查的情况下实际上无法做到这一点.某些语言功能如此普遍,以至于执行运行时检查会产生相当大的性能成本.一些严格的模式调整,再加上要求用户提交的JavaScript是严格模式代码并以某种方式调用,大大减少了对这些运行时检查的需求.

上面的引用清楚地表明在使用严格模式时会有一些性能改进.

如您所知,严格模式禁用了之前JavaScript提供的几个功能(大多数功能被认为是不好的做法).由于浏览器在使用严格模式时很容易抛出错误,因此不必执行检查并为您进行代码更正.因此,导致性能改进.


use*_*109 9

只是想加入Chetan的答案.我会指出你刚才提出的一个问题.很可能这有答案.

严格模式对您的代码做出某些假设并添加额外的检查.这些检查有两个与性能相关的效果(与普通模式相比):

  1. 需要额外的CPU时间来检查
  2. 帮助编译器理解代码并更好地优化代码.

只要2超过1,性能将在严格模式下得到改善.这对您的第一个功能起到了预期的作用.对于您的第二个功能,无法进行优化!当编译器看到不安全的参数使用时,编译器会退出.所以剩下的就是第一个效果.

我认为不可优化的代码在严格的代码中会受到更多的惩罚.额外的检查没有任何结果.