Uh oh!
There was an error while loading. Please reload this page.
EventEmitter: use a Map to store event listeners - #1785
Conversation
petkaantonov
commented
May 24, 2015
In the results you posted Map is always performing worse? |
There was a problem hiding this comment.
I believe all of these changes to readable stream are going to result in the same problem as when I proposed optimizations for eventEmitter.once() (#914), which is that some modules on npm have their readable-stream pinned to specific versions or limited version ranges. So if someone uses an older readable-stream on an io.js with these changes, things will break.
There was a problem hiding this comment.
Last I checked npm (a few weeks ago) it was only about a dozen or so? I had actually thought about submitting PRs to those projects just so we could get the .once() optimizations.
There was a problem hiding this comment.
Btw, there are other modules that are using _events directly. For example:
- https://github.com/mscdex/dicer/blob/master/lib/Dicer.js#L91
- https://github.com/mscdex/busboy/blob/master/lib/types/multipart.js#L183
- https://github.com/unshiftio/ultron/blob/master/index.js#L79
That's in my current node_modules dir, except for the readable-stream.
There was a problem hiding this comment.
@ChALkeR I was referring more generally about changes to readable-stream and how modules are depending on it version-wise, not specific code changes. But yes, there are probably a ton of modules that use _events directly.
There was a problem hiding this comment.
Last I checked npm (a few weeks ago) it was only about a dozen or so?
Just in my current node_modules dir I have 19 of those. List:
bufferstreams "readable-stream": "^1.0.33"tar-stream "readable-stream": "~1.0.33",dicer "readable-stream": "1.1.x",duplexer2 "readable-stream": "~1.1.9"through2 "readable-stream": ">=1.0.33-1 <1.1.0-0",are-we-there-yet "readable-stream": "^1.1.13"decompress-zip "readable-stream": "^1.1.8",tar-pack "readable-stream": "~1.0.2",bl "readable-stream": "~1.0.26"readdirp "readable-stream": "~1.0.26-2"busboy "readable-stream": "1.1.x"raw-body "readable-stream": "~1.0.33",gulp-bower/through2 "readable-stream": ">=1.0.28 <1.1.0-0",htmlparser2 "readable-stream": "1.1"concat-stream "readable-stream": "~1.1.9",mongodb "readable-stream": "1.0.31"read-all-stream "readable-stream": "~1.1.13"finalhandler "readable-stream": "~1.0.33",duplexify "readable-stream": "^1.1.13"There was a problem hiding this comment.
If this gets merged, will 1.0.* and 1.1.* branches of readable-stream receive patches?
If yes, it is true that there are not so many packages that specify a fixed version of readable-stream as a dependency.
ChALkeR
commented
May 24, 2015
@petkaantonov |
petkaantonov
commented
May 24, 2015
The benchmark gives results in op/s (higher is better). |
There was a problem hiding this comment.
I'm curious about performance differences with this particular change. Is it faster to keep _eventsCount around and create a new Map()?
There was a problem hiding this comment.
There is no significant performance difference if I revert ca75072. I tested with this._events.clear() and this._events = new Map()
ChALkeR
commented
May 24, 2015
Ah, that's the bundled benchmark from io.js/benchmark/events, I missed that. Something is not right here then. |
There was a problem hiding this comment.
Is this necessary? Isn't there a way to create a Map from C++?
There was a problem hiding this comment.
Maybe. I couldn't find anything related to maps in the v8 API and I know that the Map constructor is written in JS but there may be a way to call it from C++
There was a problem hiding this comment.
I see the NativeWeakMap but I can't find the regular Map either.
targos
commented
May 24, 2015
@petkaantonov is right, I assumed it was the time... |
yosuke-furukawa
commented
May 24, 2015
ES6 Map is slower than Object props in V8. And EventEmitter is our core module, if event emitter is slower, whole system may be slow on performance. |
ChALkeR
commented
May 24, 2015
@yosuke-furukawa This seems to depend on the usecase. I saw usecases where replacing objects with Maps resulted in a 2x speedup. |
yosuke-furukawa
commented
May 24, 2015
@ChALkeR Of course, the benchmark result is depend on the usecase. But current result seems to be worse. @petkaantonov is correct. our benchmark test shows |
ChALkeR
commented
May 24, 2015
@yosuke-furukawa, Yes, I know about the bundled benchmarks. |
Fishrock123
commented
May 24, 2015
Is prefixing events something that we can do without breaking anything? I think that would be a much better alternative. Map simply isn't fast enough yet. |
targos
commented
May 24, 2015
@yosuke-furukawa@Fishrock123 I agree that the current perf of Map is blocking this. |
chrisdickinson
commented
May 25, 2015
It's going to be an uphill battle to directly change the format of _events, as @mscdex noted, at minimum making sure that both minor versions of readable-stream get a backwards-compatible patch release, and propagating that through the package ecosystem. If the perf improves, I'd advise presenting a legacy _events interface via a getter and putting the map-backed interface behind a symbol or weakmap.
|
ChALkeR
commented
May 25, 2015
Btw, about the Samples:
It looks to me that there should be methods in
@mscdex, thoughts? |
mscdex
commented
May 25, 2015
@ChALkeR Using |
ChALkeR
commented
May 25, 2015
@mscdex That's why I marked that as (optional). |
mscdex
commented
May 26, 2015
@ChALkeR Well, for that you could iterate over |
chrisdickinson
commented
May 26, 2015
|
0921fb9 to
66518a0Comparesam-github
commented
May 27, 2015
Not to defend ultron - whatever it is - but introspecting an EE to see all the events that have been listened on would be very useful for debugging. For example, to check if a misspelled event name is being used. I'd like to see node be more introspectable, so if getting this info causes zero additional overhead, I think it'd be nice to have. |
Qard
commented
May 27, 2015
👍 to allowing more introspection of event emitters. |
jasnell
commented
Aug 27, 2015
targos
commented
Aug 27, 2015
@jasnell I rebased on master. here are the new benchmark numbers:
|
targos
commented
Aug 27, 2015
I guess I can close this PR for now. I don't think it will improve in a near future. |
thefourtheye
commented
Aug 27, 2015
@targos This also fixes another bug in the implementation. As of now, if we use inherited members as event names, it will confuse the events module a little. So I kinda hoped that this would land :( |
jasnell
commented
Oct 22, 2015
@targos ... Given the current status on this and your last comment, I'm inclined to close. Per @thefourtheye's comment tho, there may still be some stuff worth saving in this so perhaps another look is warranted? Particularly with the newer V8 in master? |
targos
commented
Oct 22, 2015
OK, closing for now. @thefourtheye I think the problem you are talking about can be fixed by using |
thefourtheye
commented
Oct 22, 2015
targos
commented
Oct 22, 2015
the performance tests were run in 2012. I would try with current V8 version to be sure it is still a problem. |
thefourtheye
commented
Nov 15, 2015
@targos I wrote this simple script to compare the performance of them 'use strict';consttimes=10e7;console.time('Object.create');for(vari=0;i<times;i+=1){letobj=Object.create(null);}console.timeEnd('Object.create');console.time('Object Literal');for(vari=0;i<times;i+=1){letobj={};}console.timeEnd('Object Literal');
|
This is a fix for #728.
I ran the events benchmarks to compare this with master and there seems to be a significant performance drop for some cases (though I'm not sure of how I should compare the runs).