stream: improve stream creation performance

PR-URL: https://github.com/nodejs/node/pull/19401
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Minwoo Jung <minwoo@nodesource.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
This commit is contained in:
Brian White 2018-03-16 20:35:32 -04:00 committed by Anna Henningsen
parent 1c8149417a
commit b41ed29b80
No known key found for this signature in database
GPG Key ID: 9C63F3A6CD2AD8F9
4 changed files with 74 additions and 31 deletions

View File

@ -0,0 +1,55 @@
'use strict';
const common = require('../common.js');
const Duplex = require('stream').Duplex;
const Readable = require('stream').Readable;
const Transform = require('stream').Transform;
const Writable = require('stream').Writable;
const bench = common.createBenchmark(main, {
n: [50e6],
kind: ['duplex', 'readable', 'transform', 'writable']
});
function main({ n, kind }) {
var i = 0;
switch (kind) {
case 'duplex':
new Duplex({});
new Duplex();
bench.start();
for (; i < n; ++i)
new Duplex();
bench.end(n);
break;
case 'readable':
new Readable({});
new Readable();
bench.start();
for (; i < n; ++i)
new Readable();
bench.end(n);
break;
case 'writable':
new Writable({});
new Writable();
bench.start();
for (; i < n; ++i)
new Writable();
bench.end(n);
break;
case 'transform':
new Transform({});
new Transform();
bench.start();
for (; i < n; ++i)
new Transform();
bench.end(n);
break;
default:
throw new Error('Invalid kind');
}
}

View File

@ -1,21 +0,0 @@
'use strict';
const common = require('../common.js');
const Transform = require('stream').Transform;
const inherits = require('util').inherits;
const bench = common.createBenchmark(main, {
n: [1e6]
});
function MyTransform() {
Transform.call(this);
}
inherits(MyTransform, Transform);
MyTransform.prototype._transform = function() {};
function main({ n }) {
bench.start();
for (var i = 0; i < n; ++i)
new MyTransform();
bench.end(n);
}

View File

@ -64,7 +64,7 @@ function prependListener(emitter, event, fn) {
emitter._events[event] = [fn, emitter._events[event]];
}
function ReadableState(options, stream) {
function ReadableState(options, stream, isDuplex) {
options = options || {};
// Duplex streams are both readable and writable, but share
@ -72,7 +72,8 @@ function ReadableState(options, stream) {
// However, some cases require setting options to different
// values for the readable and the writable sides of the duplex stream.
// These options can be provided separately as readableXXX and writableXXX.
var isDuplex = stream instanceof Stream.Duplex;
if (typeof isDuplex !== 'boolean')
isDuplex = stream instanceof Stream.Duplex;
// object stream flag. Used to make read(n) ignore n and to
// make all the buffer merging and length checks go away
@ -142,7 +143,11 @@ function Readable(options) {
if (!(this instanceof Readable))
return new Readable(options);
this._readableState = new ReadableState(options, this);
// Checking for a Stream.Duplex instance is faster here instead of inside
// the ReadableState constructor, at least with V8 6.5
const isDuplex = (this instanceof Stream.Duplex);
this._readableState = new ReadableState(options, this, isDuplex);
// legacy
this.readable = true;

View File

@ -48,7 +48,7 @@ util.inherits(Writable, Stream);
function nop() {}
function WritableState(options, stream) {
function WritableState(options, stream, isDuplex) {
options = options || {};
// Duplex streams are both readable and writable, but share
@ -56,7 +56,8 @@ function WritableState(options, stream) {
// However, some cases require setting options to different
// values for the readable and the writable sides of the duplex stream.
// These options can be provided separately as readableXXX and writableXXX.
var isDuplex = stream instanceof Stream.Duplex;
if (typeof isDuplex !== 'boolean')
isDuplex = stream instanceof Stream.Duplex;
// object stream flag to indicate whether or not this stream
// contains buffers or objects.
@ -201,12 +202,15 @@ function Writable(options) {
// Trying to use the custom `instanceof` for Writable here will also break the
// Node.js LazyTransform implementation, which has a non-trivial getter for
// `_writableState` that would lead to infinite recursion.
if (!(realHasInstance.call(Writable, this)) &&
!(this instanceof Stream.Duplex)) {
return new Writable(options);
}
this._writableState = new WritableState(options, this);
// Checking for a Stream.Duplex instance is faster here instead of inside
// the WritableState constructor, at least with V8 6.5
const isDuplex = (this instanceof Stream.Duplex);
if (!isDuplex && !realHasInstance.call(Writable, this))
return new Writable(options);
this._writableState = new WritableState(options, this, isDuplex);
// legacy.
this.writable = true;