Skip to content

Commit

Permalink
stream: improve stream creation performance
Browse files Browse the repository at this point in the history
PR-URL: #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>
  • Loading branch information
mscdex authored and addaleax committed Mar 23, 2018
1 parent 1c81494 commit b41ed29
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 30 deletions.
55 changes: 55 additions & 0 deletions benchmark/streams/creation.js
Original file line number Diff line number Diff line change
@@ -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');
}
}
21 changes: 0 additions & 21 deletions benchmark/streams/transform-creation.js

This file was deleted.

11 changes: 8 additions & 3 deletions lib/_stream_readable.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,16 @@ 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
// the same options object.
// 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
Expand Down Expand Up @@ -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;
Expand Down
16 changes: 10 additions & 6 deletions lib/_stream_writable.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,16 @@ 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
// the same options object.
// 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.
Expand Down Expand Up @@ -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)) {

// 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);
this._writableState = new WritableState(options, this, isDuplex);

// legacy.
this.writable = true;
Expand Down

0 comments on commit b41ed29

Please sign in to comment.