-
Notifications
You must be signed in to change notification settings - Fork 29.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
child_process: improve ipc performance #13459
Conversation
8dfec59
to
a1bd681
Compare
return (message !== null && | ||
typeof message === 'object' && | ||
typeof message.cmd === 'string' && | ||
message.cmd.length > INTERNAL_PREFIX.length && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shave off a few more millis with const INTERNALPREFIX_LENGTH = INTERNAL_PREFIX.length
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, I know it can be simplified and probably optimized, but I opted to leave it as-is for now.
function isInternal(message) { | ||
return (message !== null && | ||
typeof message === 'object' && | ||
typeof message.cmd === 'string' && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[question] since internal messages are rare, will adding a Object.hasOwnProperty(message, 'cmd') &&
fail faster than typeof message.cmd === 'string'
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know this could be simplified but I opted to leave it as-is for now.
@@ -456,16 +456,22 @@ function setupChannel(target, channel) { | |||
} | |||
chunks[0] = jsonBuffer + chunks[0]; | |||
|
|||
var nextTick = false; | |||
for (var i = 0; i < numCompleteChunks; i++) { | |||
var message = JSON.parse(chunks[i]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not check for isInternal
on the raw chunk?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It has to be parsed first. chunks
here is just an array of (complete) JSON strings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant implement a string based check. Can't we assume "innerMessages" will have a {cmd: NODE_
prefix? or at least include a , cmd: NODE_
substring? Might also be able to distinguish between three cases: user/inner/inner_with_handle, and turn the following compound if
into a switch
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather not make assumptions about JSON.stringify()
output.
target.emit(eventName, message, handle); | ||
}); | ||
function isInternal(message) { | ||
return (message !== null && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
even if we don't do a string based check, returning 0,1,2 (for user / inner / NODE_HANDLE) will enable using a switch
in L466
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's unlikely it'll matter much, I'll let someone else work on it if they want. My main focus on this PR is nextTick()
usage.
@mscdex Thanks for the answers 🎩 |
Results with V8 5.9 now in master:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice optimization, LGTM.
return; | ||
} | ||
for (id in cluster.workers) { | ||
const worker = cluster.workers[id]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nothing wrong with this but you could ES6-ify it with for (const worker of Object.values(cluster.workers))
. Whatever your preference.
I suppose it could even be a little faster because Object.values()
doesn't walk the prototype chain but that's probably only a marginal benefit (and I didn't test so my intuition might very well be wrong.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW I literally copied it from the cluster
docs. I know we were trying to be more on the conservative side when it comes to introducing ES* features to benchmarks because of possible incompatibilities with older branches. For example, Object.values()
does not exist in node v4.x or v6.x (although it's apparently behind a flag in recent v6.x releases).
PR-URL: nodejs#13459 Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
PR-URL: nodejs#13459 Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
a1bd681
to
8208fda
Compare
PR-URL: #13459 Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
PR-URL: #13459 Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
This commit fixes a regression related to IPC 'message' events. When messages are not emitted in the next tick, a 'message' handler that throws can break the IPC read loop. Refs: nodejs#6909 Refs: nodejs#13459 Refs: nodejs#13648 PR-URL: nodejs#13856 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
This commit fixes a regression related to IPC 'message' events. When messages are not emitted in the next tick, a 'message' handler that throws can break the IPC read loop. Refs: #6909 Refs: #13459 Refs: #13648 PR-URL: #13856 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
This commit fixes a regression related to IPC 'message' events. When messages are not emitted in the next tick, a 'message' handler that throws can break the IPC read loop. Refs: #6909 Refs: #13459 Refs: #13648 PR-URL: #13856 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
should this land in LTS? If so it will need to bake a bit longer. Please change labels as appropriate |
This commit fixes a regression related to IPC 'message' events. When messages are not emitted in the next tick, a 'message' handler that throws can break the IPC read loop. Refs: #6909 Refs: #13459 Refs: #13648 PR-URL: #13856 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
These commits reduce/improve
nextTick()
usage in thechild_process
IPC implementation.I should point out that I wasn't sure if we should ever need
nextTick()
when receiving/emitting messages, so for now I just made sure that both all internal messages and only the first non-internal message in a group are emitted within the same tick.There is a substantial performance improvement when removing
nextTick()
altogether for emitted messages. My thought was that these messages should always happen on at least the next tick anyway, so perhaps it would be safe to remove it completely? All tests pass withnextTick()
completely removed fromhandleMessage()
.Results with the current changes with the included benchmark:
CI: https://ci.nodejs.org/job/node-test-pull-request/8473/
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected core subsystem(s)