3 ms·
Holy crap! I just had to check this and you are completely correct. map() is 10x slower in Chromium than overwriting an array. Interestingly, writing my own
by mikekchar 10y ago
Holy crap! I just had to check this and you are completely correct. map() is 10x slower in Chromium than overwriting an array. Interestingly, writing my own map operation in JS (by creating a new array and mutating it) was only 20% slower than mutating the original array. So something is very, very, very wrong with Array.map() on Chromium...
Then I checked it on Firefox. My hand-rolled map function is 3 times slower than the mutating version and the map() version is 1 or 2 orders of magnitude faster than the mutating version (as you would expect it to be).
So there is something wrong with Chromium, I think... Caveat: First thing in the morning on boxing day, back of the envelope style hacking. Having someone else verify my results would be nice ;-) Otherwise take it with a grain of salt...
Edit: The built in profiler was giving me strange results on Firefox, so I used the Gecko Profiler extension and it gave me something more reasonable: map() is about 50% slower than mutating the array and my handrolled map is about 20% slower than mutating the array. So that's a bit more consistent with Chromium's results.
- Isobit 10y agoMind sharing the code you were testing this with? I have actually seen map perform better than for loops in Chrome in some cases (see https://www.measurethat.net/Benchmarks/Show/1096/0/map-vs-for-loop https://www.measurethat.net/Benchmarks/Show/1096/0/map-vs-fo...).
- mikekchar 10y agoIt's very trivial (this is the bulk of it -- not showing everything to spare people from jumping over a huge message): var f = function f(num) { return num + 5; } var immutable = function immutable(arr) { return arr.map(f); } var mutating = function mutating(arr) { var i = 0; var l = arr.length; for(; i < l; i++) { arr[i] = f(arr[i]); } return arr; } In my actual code, arr is a array of ascending numbers from 1 to 10,000 (different sized array each set of calls). I rebuild it before each call to immutable and mutating. I then run each of those functions, one after another 10,000 times. The intent is to make sure that there are no strange optimisations with a constant array and to even out the impact of the GC by interleaving the calls. Unfortunately I tried to go to the link that you provided, but it just timed out :-( Ah... it showed up. Hard to say what's going on there. I can't see the source code of how the benchmark works. But I do notice that you aren't returning the values. It is entirely possible that the code is being optimised out. I recommend returning the array. I also added up the elements of the array and checked that each implementation added up to the same number, just to make sure that the operation was actually performed.
- Isobit 10y agoInteresting. I did add a return to that benchmark and it didn't seem to affect the results. I would think your test would be identical to mine in performance characteristics, I wonder if it's just the benchmarking methods leading to the difference. I might just go write my own benchmarking like yours since I don't really know what measurethat.net is doing. It seems intuitively obvious that map would be less efficient, but who knows what V8 is doing to optimize under the hood.
- mikekchar 10y agoGiven that they are so close in your example, I was thinking that it's possible that both sides are being optimised out, but that since the map side is smaller, it runs faster (i.e. the optimisation is at run time and so it still has to interpret the code -- smaller code interprets faster). I haven't had time to revisit this since, but I think it's important. It is also possible that the profiling support in Chromium and Firefox is broken and I would very much like to know that if it is true.