-
Notifications
You must be signed in to change notification settings - Fork 29.7k
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
events: don't keep arrays with a single listener #12043
Conversation
I fear this could cause userland issues like when I tried to change the internal storage structure when optimizing |
@mscdex care to elaborate? This doesn't change internal structures, it keeps them consistent (1 listener - no array, 2+ listeners - array). If people use |
lib/events.js
Outdated
do { | ||
this.removeListener(type, listeners[listeners.length - 1]); | ||
} while (listeners[0]); | ||
for (i = listeners.length; i-- > 0;) { |
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'm not a big fan of this notation tbh. Why not move the --
operation to the 3rd chunk of the for-structure?
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've used that because the same is done few lines above: https://github.com/nodejs/node/pull/12043/files#diff-71dcd327d0ca067b490b22d677f81966R366.
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.
Oh wow. Would love to see some feedback from one or two other @nodejs/collaborators on this. You're re-using this pattern here (where it wasn't here before). Do we really want to embrace that pattern or move away from it?
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 agree, this pattern is hard to understand. Let's change it in both places to something simpler.
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.
Looks like this is the only place in core we use this pattern (although it appears a few times in v8 c++ code. It was added in 3e64b56. I think we should remove this and just use the standard for loop style.
➜ rg "i[-|+]+ [<|>]" | grep for
lib/events.js: for (i = list.length; i-- > 0;) {
deps/v8/src/deoptimizer.cc: for (size_t i = count; i-- > 0;) {
deps/v8/src/ast/ast-types.cc: for (size_t i = BoundariesSize() - 1; i-- > 0;) {
deps/v8/src/full-codegen/full-codegen.cc: for (int i = last; i-- > 0;) {
deps/v8/src/compiler/types.cc: for (size_t i = BoundariesSize() - 1; i-- > 0;) {
deps/v8/src/parsing/parser.cc: for (int i = labels->length(); i-- > 0;) {
deps/openssl/openssl/crypto/store/str_lib.c: for (i = 0; i++ < STORE_ATTR_TYPE_NUM;)
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.
🔧 in ca87422.
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.
Thanks guys 👍
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 the same pattern is also used here
node/benchmark/events/ee-add-remove.js
Line 19 in 678480e
for (k = listeners.length; --k >= 0; /* empty */) |
Does this affect performance? Can you please run https://github.com/nodejs/node/tree/master/benchmark/events? |
@mcollina yes will do as soon as my internet connection will start working again. |
|
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.
LGTM, can you add that we get some speedup in the commit message?
ca87422
to
8979815
Compare
@mcollina done, I've only mentioned the events/ee-once.js benchmark as I can't really see how this change could make a difference in events/ee-listeners.js or events/ee-emit.js. |
It might be better to add some new benchmarks and refer to the results of those since the current benchmarks should not be affected by this PR's changes (except maybe ee-add-remove). |
Agreed. ee-add-remove is actually a good benchmark for these changes. I'll remove the misleading info from commit message. |
8979815
to
ac61a0a
Compare
Use the remaining listener directly if the array of listeners has only one element after running `EventEmitter.prototype.removeListener()`. Advantages: - Better memory usage and better performance if no new listeners are added for the same event. Disadvantages: - A new array must be created if new listeners are added for the same event.
ac61a0a
to
1b027c1
Compare
This ad-hoc benchmark shows no difference in performance between master and this PR. 'use strict';
var common = require('../common.js');
var events = require('events');
var bench = common.createBenchmark(main, {n: [1e6]});
function main(conf) {
var n = conf.n | 0;
var ee = new events.EventEmitter();
function listener1() {}
function listener2() {}
ee.on('removeListener', function() {});
bench.start();
for (var i = 0; i < n; i++) {
ee.on('dummy', listener1);
ee.on('dummy', listener2);
ee.removeListener('dummy', listener2);
ee.emit('dummy', 'arg');
ee.on('dummy', listener2);
ee.removeAllListeners('dummy');
}
bench.end(n);
} Taking the best result over multiple runs I get
for master and
for this PR. |
@lpinca Then I guess one of the advantages mentioned in the description of this PR (performance) is not really valid. I think the consistency argument is valid though. |
@ronkorving well if I craft the benchmark to only remove The benchmark also readd |
@lpinca Oh wow, interesting 👍 |
If there are no objections I'll land this tomorrow. cc: @nodejs/collaborators |
LGTM 👍 |
Use the remaining listener directly if the array of listeners has only one element after running `EventEmitter.prototype.removeListener()`. Advantages: - Better memory usage and better performance if no new listeners are added for the same event. Disadvantages: - A new array must be created if new listeners are added for the same event. PR-URL: #12043 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Daijiro Wachi <daijiro.wachi@gmail.com> Reviewed-By: Ron Korving <ron@ronkorving.nl>
Landed in 8d386ed |
Use the remaining listener directly if the array of listeners has only one element after running `EventEmitter.prototype.removeListener()`. Advantages: - Better memory usage and better performance if no new listeners are added for the same event. Disadvantages: - A new array must be created if new listeners are added for the same event. PR-URL: nodejs#12043 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Daijiro Wachi <daijiro.wachi@gmail.com> Reviewed-By: Ron Korving <ron@ronkorving.nl>
looks like something we may want on v6.x, want to give it a bit more time to bake first |
Commit 8d386ed stopped the Event Emitter implementation from storing arrays containing a single listener. This change left a section of code in removeListener() as unreachable. This commit removes the unreachable code. Refs: nodejs#12043 PR-URL: nodejs#12501 Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
Commit 8d386ed stopped the Event Emitter implementation from storing arrays containing a single listener. This change left a section of code in removeListener() as unreachable. This commit removes the unreachable code. Refs: nodejs#12043 PR-URL: nodejs#12501 Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
Use the remaining listener directly if the array of listeners has only one element after running `EventEmitter.prototype.removeListener()`. Advantages: - Better memory usage and better performance if no new listeners are added for the same event. Disadvantages: - A new array must be created if new listeners are added for the same event. PR-URL: #12043 Backport-PR-URL: #13796 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Daijiro Wachi <daijiro.wachi@gmail.com> Reviewed-By: Ron Korving <ron@ronkorving.nl>
Commit 8d386ed stopped the Event Emitter implementation from storing arrays containing a single listener. This change left a section of code in removeListener() as unreachable. This commit removes the unreachable code. Refs: #12043 PR-URL: #12501 Backport-PR-URL: #13796 Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
Use the remaining listener directly if the array of listeners has only one element after running `EventEmitter.prototype.removeListener()`. Advantages: - Better memory usage and better performance if no new listeners are added for the same event. Disadvantages: - A new array must be created if new listeners are added for the same event. PR-URL: #12043 Backport-PR-URL: #13796 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Daijiro Wachi <daijiro.wachi@gmail.com> Reviewed-By: Ron Korving <ron@ronkorving.nl>
Commit 8d386ed stopped the Event Emitter implementation from storing arrays containing a single listener. This change left a section of code in removeListener() as unreachable. This commit removes the unreachable code. Refs: #12043 PR-URL: #12501 Backport-PR-URL: #13796 Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
Use the remaining listener directly if the array of listeners has only one element after running `EventEmitter.prototype.removeListener()`. Advantages: - Better memory usage and better performance if no new listeners are added for the same event. Disadvantages: - A new array must be created if new listeners are added for the same event. PR-URL: nodejs/node#12043 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Daijiro Wachi <daijiro.wachi@gmail.com> Reviewed-By: Ron Korving <ron@ronkorving.nl>
Use the remaining listener directly if the array of listeners has only one element after running
EventEmitter.prototype.removeListener()
.Advantages:
Disadvantages:
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected core subsystem(s)
events