使用节点,为什么代码用“严格使用”这么快?

我从来不知道use strict来加速运行时间,但简单的use strict使得我的基准testing速度大大加快,而较慢的testing速度明显较慢(超过两倍)。 这是怎么回事?

 // // 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。 这是我正在使用本指南 加速节点thunkify的所有工作的一部分。 有趣的是蓝鸟优化指南并没有提到use strict; 有利的performance。

更多的是,如果我改变testing用例,

 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) 

这个缓慢的原因是在ArraySlice内build的这个检查中 。 它testing我们是否试图分割参数对象,如果我们这样做,然后使用一个快速的代码来做到这一点。 但是它只检查马虎模式参数对象。 当你在严格函数中分配参数对象时,你会得到由native_context()->strict_arguments_boilerplate() 严格模式参数对象,这意味着上面的检查不能识别它,而是落入比专门的手写代码慢的通用JavaScript代码C ++快速path它将需要一个马虎参数对象。

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

JavaScript的灵活性使得在没有许多运行时检查的情况下做到这一点是不可能的 某些语言function非常普遍,执行运行时检查具有相当大的性能成本。 一些严格的模式调整,再加上要求用户提交的JavaScript是严格的模式代码,并以某种方式调用,大大减less了对运行时检查的需求。

上面的引用很清楚地表明,在使用严格模式的时候有一定的性能提升。

如您所知,严格模式会禁用JavaScript以前提供的几个function(其中大多数被认为是不好的做法)。 由于浏览器在使用严格模式时很容易出错,因此无需执行检查并假定代码更正。 因此,导致性能改进。

只是想补充Chetan的答案。 我会指出你刚刚提出的一个问题 。 这很可能有答案。

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

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

在严格模式下,性能将得到提高,只要2超过1.这可以按照您的第一个function预期的那样工作。 对于你的第二个function,不能进行优化! 当编译器看到不安全的参数使用情况时,编译器会自动退出。 所以第一个效果就是剩下的

我认为不可优化的代码在严格的代码中要花费更多的代价。 额外的检查什么都没有。