Skip to content

Commit

Permalink
workers: refactor stdio to improve performance
Browse files Browse the repository at this point in the history
Signed-off-by: Matteo Collina <[email protected]>
  • Loading branch information
mcollina committed Jan 16, 2025
1 parent f4fcf0e commit 159cd0d
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 13 deletions.
6 changes: 4 additions & 2 deletions lib/internal/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -339,9 +339,11 @@ class Worker extends EventEmitter {
{
const { stream, chunks } = message;
const readable = this[kParentSideStdio][stream];
ArrayPrototypeForEach(chunks, ({ chunk, encoding }) => {
// This is a hot path, use a for(;;) loop
for (let i = 0; i < chunks.length; i++) {
const { chunk, encoding } = chunks[i];
readable.push(chunk, encoding);
});
}
return;
}
case messageTypes.STDIO_WANTS_MORE_DATA:
Expand Down
34 changes: 23 additions & 11 deletions lib/internal/worker/io.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';
'use strict'

Check failure on line 1 in lib/internal/worker/io.js

View workflow job for this annotation

GitHub Actions / lint-js-and-md

Missing semicolon

const {
Array,
ArrayPrototypeForEach,

Check failure on line 5 in lib/internal/worker/io.js

View workflow job for this annotation

GitHub Actions / lint-js-and-md

'ArrayPrototypeForEach' is assigned a value but never used
ArrayPrototypeMap,

Check failure on line 6 in lib/internal/worker/io.js

View workflow job for this annotation

GitHub Actions / lint-js-and-md

'ArrayPrototypeMap' is assigned a value but never used
ArrayPrototypePush,

Check failure on line 7 in lib/internal/worker/io.js

View workflow job for this annotation

GitHub Actions / lint-js-and-md

'ArrayPrototypePush' is assigned a value but never used
Expand Down Expand Up @@ -77,7 +78,7 @@ const kOnMessage = Symbol('kOnMessage');
const kOnMessageError = Symbol('kOnMessageError');
const kPort = Symbol('kPort');
const kWaitingStreams = Symbol('kWaitingStreams');
const kWritableCallbacks = Symbol('kWritableCallbacks');
const kWritableCallback = Symbol('kWritableCallback');
const kStartedReading = Symbol('kStartedReading');
const kStdioWantsMoreDataCallback = Symbol('kStdioWantsMoreDataCallback');
const kCurrentlyReceivingPorts =
Expand Down Expand Up @@ -282,20 +283,29 @@ class WritableWorkerStdio extends Writable {
super({ decodeStrings: false });
this[kPort] = port;
this[kName] = name;
this[kWritableCallbacks] = [];
this[kWritableCallback] = null;
}

_writev(chunks, cb) {
const toSend = new Array(chunks.length);

// We avoid .map() because it's a hot path
for (let i = 0; i < chunks.length; i++) {
const { chunk, encoding } = chunks[i];
toSend[i] = { chunk, encoding };
}

this[kPort].postMessage({
type: messageTypes.STDIO_PAYLOAD,
stream: this[kName],
chunks: ArrayPrototypeMap(chunks,
({ chunk, encoding }) => ({ chunk, encoding })),
chunks: toSend,
});
if (process._exiting) {
cb();
} else {
ArrayPrototypePush(this[kWritableCallbacks], cb);
// Only one writev happens at any given time,
// so we can safely overwrite the callback.
this[kWritableCallback] = cb;
if (this[kPort][kWaitingStreams]++ === 0)
this[kPort].ref();
}
Expand All @@ -311,11 +321,13 @@ class WritableWorkerStdio extends Writable {
}

[kStdioWantsMoreDataCallback]() {
const cbs = this[kWritableCallbacks];
this[kWritableCallbacks] = [];
ArrayPrototypeForEach(cbs, (cb) => cb());
if ((this[kPort][kWaitingStreams] -= cbs.length) === 0)
this[kPort].unref();
const cb = this[kWritableCallback];
if (cb) {
this[kWritableCallback] = null;
cb();
if ((--this[kPort][kWaitingStreams] ) === 0)

Check failure on line 328 in lib/internal/worker/io.js

View workflow job for this annotation

GitHub Actions / lint-js-and-md

There should be no space before this paren
this[kPort].unref();
}
}
}

Expand Down

0 comments on commit 159cd0d

Please sign in to comment.