node.js optimization v8 strict

node.js - Usando el nodo, ¿por qué el código es mucho más rápido con "uso estricto"?



optimization v8 (3)

A continuación hay una cita del artículo de Mozilla sobre el modo estricto de JavaScript.

La flexibilidad de JavaScript hace que sea efectivamente imposible hacerlo sin muchas comprobaciones de tiempo de ejecución. Ciertas funciones de lenguaje son tan generalizadas que realizar verificaciones en tiempo de ejecución tiene un costo de rendimiento considerable. Algunos ajustes de modo estricto, además de exigir que el código de modo estricto de JavaScript enviado por el usuario y que se invoque de cierta manera, reducen sustancialmente la necesidad de esas verificaciones de tiempo de ejecución.

La cita anterior deja bastante claro que hay ciertas mejoras de rendimiento al usar el modo estricto.

Como sabe, el modo estricto deshabilita varias funciones que JavaScript proporcionó anteriormente (la mayoría de ellas se consideran una mala práctica). Dado que el navegador puede generar errores fácilmente al usar el modo estricto, no tiene que realizar comprobaciones ni asumir correcciones de código por usted. Por lo tanto, dando lugar a mejoras de rendimiento.

Nunca supe un use strict para acelerar el tiempo de ejecución, sin embargo, un simple use strict es hacer que mi índice de referencia sea sustancialmente más rápido, y el más lento es mucho más lento (más del doble de lento). ¿Que esta pasando?

// // 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();

Sin ese "use strict" , los resultados están en línea con esto,

$ 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

Sin embargo, con ese "use strict;" , Estoy recibiendo esto,

$ 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

Estoy ejecutando nodejs v0.11.13. Todo esto es parte del trabajo que estoy haciendo para acelerar el nodo-thunkify usando esta guía . Curiosamente la guía de optimización de bluebird no menciona el use strict; El rendimiento beneficioso.

Jugando un poco más con él, si cambio el caso de prueba para ser,

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();

por lo tanto, eliminando las llamadas thunkify todavía veo lo mismo ... El caso con uso estricto es más lento en el código no optimizado, y más rápido en el código optimizado,

No estricto

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)

"uso estricto";

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)


El motivo de esta lentitud se encuentra en este chequeo dentro de ArraySlice incorporado. Comprueba si estamos tratando de dividir los argumentos del objeto y, si lo hacemos, utiliza un código rápido para hacerlo. Sin embargo, solo comprueba el objeto de argumentos en modo descuidado . Cuando asigna un objeto de argumentos dentro de la función estricta, obtiene un objeto de argumentos de modo estricto creado a partir de native_context()->strict_arguments_boilerplate() que significa que la verificación anterior no lo reconoce y se native_context()->strict_arguments_boilerplate() al código genérico de JavaScript, que es más lento que el código manual especializado. Ruta rápida de C ++ que tomaría para un objeto de argumentos descuidados.


Solo quería agregar a la respuesta de Chetan. Le señalaré una question que había hecho poco tiempo atrás. Lo más probable es que esto tenga la respuesta.

El modo estricto realiza ciertas suposiciones acerca de su código y agrega controles adicionales. Estas verificaciones tienen dos efectos relacionados con el rendimiento (en comparación con el modo normal):

  1. Tómese tiempo extra de CPU para verificar
  2. Ayuda al compilador a entender el código y optimizarlo mejor.

El rendimiento mejorará en modo estricto siempre que 2 sean mayores que 1. Esto funciona como se esperaba para su primera función. ¡Para su segunda función no se pueden hacer optimizaciones! El compilador se rescata cuando ve un uso inseguro de argumentos. Así que el primer efecto es todo lo que queda.

Supongo que el código no optimizable requiere mucha más penalización en el código estricto. Los cheques adicionales no dan nada.