-
Notifications
You must be signed in to change notification settings - Fork 30k
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: improve eventEmitter.once() performance #5127
Conversation
LGTM |
Ok, assuming people would be ok with the change itself, how about updating /cc @nodejs/collaborators |
So the way readable streams works is we pull from the published version of node after it publishes, so we can do one of couple things
|
Just a quick question: does it introduce some slowdown on normal Does it impact streams (net, http, fs) as they are? Are those faster (or slower) because of this? |
I'm still kind of -0 on this - it stands to break anyone that has pegged a version of readable-stream even if we release a patch version of that package. Maybe putting it through CITGM first would be good?
|
@chrisdickinson IMHO even if this PR doesn't get landed, I think that we should remove streams' reliance on EventEmitter's implementation details. Doing so would allow optimizations like the one in this PR to not have the problem we currently face. |
so maybe we land the streams update first and ensure it does not impact performance and then as a step 2/separate thing look into updating events |
There are a couple of performance regressions, one of which I have already solved (and actually turned the regression into a significant improvement in the process). I am working on the other. |
This commit improves once() performance by avoiding the creation of wrapper functions. These changes bring ~51% increase in performance when simply adding once() event handlers, ~205% increase in the included ee-emit-once benchmark, and a ~36% increase in the included ee-add-remove-once benchmark. This commit also adds new benchmarks, bumps the default number of iterations for several of the existing benchmarks, and also adds missing forced optimizations.
0f23be8
to
3e38006
Compare
Ok I've worked on this some more the past couple of days and I was able to minimize the impact as much as possible (at least as much as I can tell). Here are the results I'm currently getting with master:
|
I am LGTM once address the breakage this will cause to readable-stream users. |
Just for fun I created an alternative implementation (that instead stores once handler count by event name on a separate object property) that trades a bit of performance on some benchmarks for compatibility with the existing readable stream implementation:
|
I've added a new |
@jasnell I propose we introduce this in the first cut of v7, and we will deal with the breakage. |
The primary area of concern is with streams right? /cc @nodejs/streams |
@jasnell Pretty much, or anyone else that is directly inserting new events via |
I'm wondering if at some point we should use a different internal for |
@jasnell That will probably only work for so long until people probably just end up doing a find-replace with whatever the new property name is to "fix" their scripts. |
if ((list.once || list) === listener) { | ||
if (--this._eventsCount === 0) | ||
this._events = {}; | ||
else { |
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.
ditto on keeping braces the same.
Unfortunately there are more than a few implementation details devs rely on that we can't freely change. This is known to be used in the wild. We should do some brief analysis to see the ecosystem impact because of this. I think APM's might take issue with this. |
c133999
to
83c7a88
Compare
ping @mscdex |
@jasnell Still stalled until at least the following are remedied:
Additionally, I haven't ran benchmarks to compare these changes with the current |
It would be nice to get the breakdown of the download numbers for each version, not sure who to ask at npm. This is fixed on @mscdex can we get a slower but compatible way to implement this API (maybe with a getter or a Proxy) that will be compatible? |
ping @jasnell |
I think we might want to update this PR and get a fresh run of CITGM. I'm actually 👍 of making this change in Node.js 8, pending a passing CITGM run. However, a safer approach might be to wait until 8 is cut and we start working on 9. cc @nodejs/streams. |
I'd also suggest we run this with V8 60 and not current master (V8 58) to make sure the performance improvements still hold. |
@fhinkel It will probably be awhile yet before something like this could land since the main issue (AFAIK) still is modules/users that depend on older versions of |
@mcollina I don't know. It's going to be hard to gauge with end users of course (modules will be easier to spot on npm). Does @nodejs/ctc have any opinion? |
@mscdex I am referring to download stats from npm. I helped migrate the mysql module as well (it's still not released yet mysqljs/mysql#1677). A solution might be to backport the fix to the 1.x line of readable-stream. |
@mcollina Ah ok, I was referring to actually collecting data on Even updating |
@mscdex it will be a long process. If you can't find that script, we might rewrite it and actively send PRs over. |
@mscdex Should this remain open? Should some or all of the benchmark changes be landed? |
@Trott Yes, the problem/"blocker" is still the same. |
Not limited to this PR, but I think everything labeled |
@mscdex would it be possible to split this PR into two - one without breaking changes and one with? If that would be possible and the one without BC would still yield a performance improvement, I think it would be worth pursuing that instead of having the PR stalled for a very long time. |
I am relatively certain that the performance benefit will be much less with newer V8 versions. As this is one of the oldest PRs and it seems like there is little progress and more and more conflicts are coming up due to changes in the code over time I am going ahead and close this. @mscdex if you feel like this should stay open, please go ahead and reopen. |
This commit improves once() performance by storing the event handler directly instead of creating a wrapper function every time.
These changes bring ~150% increase in performance when simply adding once() event handlers, ~220% increase in the included ee-emit-once benchmark, and a ~50% increase in the included ee-add-remove-once benchmark.
This PR is #914 rebased on master.
The backwards compatibility issue (with directly modifying the private
_events
property) withreadable-stream
still stands however. We would need to get package owners who have a pegged dependency version forreadable-stream
to either bump the version (to thereadable-stream
version containing the changes from this PR) or use a less strict specifier.