为什么在JavaScript(v8)中,对于整数键,"Map "操作比 "Object "慢很多?

问题描述 投票:1回答:1

我曾愉快地使用 Map 为我的JavaScript代码库中随处可见的索引访问,但我只是偶然发现了这个基准。https:/stackoverflow.coma54385459365104

我在这里也重新制作了一下。https:/jsben.chHOU3g

benchmark所做的基本上是在地图上填充1M个元素,然后对它们进行迭代。

我希望Map和Object的结果是对等的,但是它们有很大的不同--有利于Object。

这是预期的行为吗?可以解释一下吗?是因为排序要求吗?还是因为Map做了一些密钥散列?或者只是因为Map允许任何对象作为key(我希望它使用指针地址作为key,而不需要任何散列)?Map和Object的索引算法有什么区别?

这很出乎我的意料,也很令人沮丧--基本上,我不得不回到老派的 "对象即地图 "的编码风格。

更新#1

正如评论中所建议的那样,Object可能会被优化为Array(因为它是由整数索引的,从0开始)。

将迭代顺序从 size0 - 对象仍是 2倍速度. 当使用字符串作为索引时,Map的表现要好2倍。

javascript performance dictionary object v8
1个回答
4
投票

(V8开发者在此。)

我必须恢复到老派的 "对象即地图 "的编码风格。

如果你这样做,你将成为一个误导性的微基准的受害者。

在使用连续整数作为键的非常特殊的情况下,一个普通的 Object 会更快,是的。在这种情况下,没有什么比连续数组更胜一筹。所以,如果你提到的 "在你的代码库中到处都是索引访问 "确实是使用0到1M的整数这样的索引集,那么使用Object或者Array是一个好主意。但这是一种特殊情况。如果索引空间是稀疏的,事情就已经显得不一样了。

在一般情况下,使用随机顺序的任意字符串,一个 Map 的性能将明显优于一个 Object. 更重要的是,处理这种对象属性访问的方式(在V8中,很可能在其他引擎中也是如此)已经是 非本地 效果:如果一个函数给对象属性查找处理系统的慢路带来了过大的压力,那么很可能会拖慢一些 其他 函数依靠相同的慢路径来进行属性访问。

根本原因是,引擎针对不同的使用模式优化不同的东西。一个引擎 可以 对象和地图的实现在本质上几乎是一样的;但这并不是理想的行为,因为不同的使用模式从不同的内部表示和实现选择中受益。所以引擎允许你为他们提供一个提示:如果你使用一个 Map引擎会知道你打算把这个东西当做一张地图来使用(duh!),在那里随机键会来来去去。如果你使用一个 Object那么引擎将(至少在一开始)假设你想要的优化集对你的普通对象最有效,其中属性集是相当小的和静态的。如果你使用一个 Array (或 Object 只有整数属性,这在JS中几乎是一样的),那么你就可以让引擎很容易地给你快速的整数索引访问。

使用 "x" + i 作为关键是一个很好的建议,可以证明如何快速改变一个微基准,使其看起来产生相反的结果。但这里有一个破坏性因素:如果你做了(仅)这个修改,那么你所测量的很大一部分将是数字到字符串的转换和字符串内化,而不是MapObject访问性能本身。

小心微基准,它们具有误导性。 你真的必须对它们进行深入分析(通过剖析,或者通过检查生成的代码,或者通过追踪其他引擎的内部结构),以确定它们测量的是你认为它们在测量的东西,因此产生的结果是告诉你你认为它们在告诉你的东西。

一般来说,强烈建议使用 代表性 性能测量的测试用例。理想的情况是,你的应用本身;或者通过将其现实的一部分提取到一个在现实数据上运行的测试用例中。而如果你不能用压力测试来测量你的整个生产应用的两个实现选择之间的差异,那么这不是一个值得担心的差异。通过一个微型benchmark(即几条人工制作的线路),我几乎可以 "证明 "任何不适用于一般情况的东西。

© www.soinside.com 2019 - 2024. All rights reserved.