【问题标题】:Using node, why is code so much faster with "use strict"?使用节点,为什么使用“使用严格”的代码要快得多?
【发布时间】:2014-07-22 17:34:30
【问题描述】:

我从来不知道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。这是我使用this guidespeed up node-thunkify 所做的全部工作。有趣的是,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 我仍然看到同样的事情。使用严格的情况在未优化的代码上速度较慢,在优化的代码上速度更快,

不严格

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)

【问题讨论】:

  • 你看过这个吗?具体而言,“使用严格”如何执行以下“它会禁用令人困惑或考虑不周的功能”。 stackoverflow.com/questions/1335851/…
  • 为什么禁用这些功能会使未优化函数的运行时间大大变慢,而优化函数的运行时间却快>10%?
  • 我能得出的唯一结论是,strict 必须以某种方式减缓对 arguments 的修改,并加速简单的迭代和元素分配......

标签: node.js optimization v8 strict


【解决方案1】:

以下引用来自Mozilla's article on JavaScript Strict Mode

JavaScript 的灵活性使得它实际上不可能做到这一点 没有很多运行时检查。某些语言功能是如此 普遍认为执行运行时检查具有相当大的性能 成本。一些严格的模式调整,加上要求用户提交 JavaScript 是严格模式的代码,并且它在某个特定的情况下被调用 方式,大大减少对这些运行时检查的需求。

上面的引用非常清楚地表明,在使用严格模式时会有一定的性能改进。

如您所知,严格模式会禁用 JavaScript 之前提供的一些功能(其中大部分被认为是不好的做法)。由于浏览器在使用严格模式时很容易抛出错误,因此它不必为您执行检查和假设代码更正。因此,可以提高性能。

【讨论】:

    【解决方案2】:

    这种缓慢的原因在于 ArraySlice 内置的this check。它测试我们是否尝试对参数对象进行切片,如果这样做,则使用快速代码来执行此操作。但是它只检查 sloppy mode 参数对象。当您在严格函数中分配参数对象时,您会得到由native_context()-&gt;strict_arguments_boilerplate() 制成的 严格模式 参数对象,这意味着上面的检查无法识别它并落入比专门手慢的通用 JavaScript 代码- 编码的 C++ 快速路径,它将用于一个草率的参数对象。

    【讨论】:

      【解决方案3】:

      只是想补充一下 Chetan 的答案。我会给你指一个question你不久前问过的。这很可能有答案。

      严格模式会对您的代码做出某些假设并添加额外的检查。这些检查对性能有两个影响(与正常模式相比):

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

      在严格模式下,只要 2 大于 1,性能就会提高。这对您的第一个函数可以正常工作。对于您的第二个功能,无法进行任何优化!当编译器看到不安全的参数使用时,它会退出。所以第一个效果就是剩下的。

      我猜不可优化的代码在严格的代码中会受到更多的惩罚。额外的检查一无所获。

      【讨论】:

        猜你喜欢
        • 2016-02-10
        • 2015-06-27
        • 2023-01-02
        • 1970-01-01
        • 2015-05-06
        • 2010-12-17
        • 1970-01-01
        • 2011-08-28
        • 1970-01-01
        相关资源
        最近更新 更多