JavaScript:为什么map.has比set.has和array.indexOf快这么多?

2024-02-19

我遇到了以下基准:https://jsperf.com/array-includes-and-find-methods-vs-set-has https://jsperf.com/array-includes-and-find-methods-vs-set-has如果你执行它,你会看到map.has是迄今为止在浏览器中查找集合中项目的最有效方法。

我还在 Node 中使用重新创建了这个测试benchmarks.js,并得到以下结果:

节点9.4.0:

set.has x 6,454,428 ops/sec ±1.25% (90 runs sampled)
map.has x 64,519,657 ops/sec ±0.95% (86 runs sampled)
arr.includes x 11,415,721 ops/sec ±1.41% (87 runs sampled)
arr.indexOf x 11,344,587 ops/sec ±1.39% (87 runs sampled)
arr.find x 1,579,635 ops/sec ±1.09% (92 runs sampled)
Fastest is map.has

节点6.2.0:

set.has x 16,677,473 ops/sec ±1.35% (86 runs sampled)
map.has x 15,089,503 ops/sec ±1.35% (85 runs sampled)
arr.includes x 1,345,019 ops/sec ±1.31% (89 runs sampled)
arr.indexOf x 15,943,213 ops/sec ±4.40% (80 runs sampled)
arr.find x 1,423,994 ops/sec ±2.05% (82 runs sampled)
Fastest is set.has,arr.indexOf

这些结果对我来说非常令人惊讶,有谁知道:

  1. 怎么会map.has比 快 10 倍set.has几乎快 6 倍array.indexOf?

  2. 在节点 6 中,includes似乎比慢得多indexOf, and arr.find(val => val === 1)是相同的arr.includes(1). Why?

  3. set.hasNode 9 中的速度似乎比 Node 6 中的速度要慢,这是为什么呢?


UPDATE

现在V8有ReduceSetPrototypeHas方法,因此它将在较新版本的 Node.js 或浏览器中进行优化。

https://github.com/v8/v8/commit/4c81827c8d6ca1d3d9b0cb6a2ef1264eb0f59524 https://github.com/v8/v8/commit/4c81827c8d6ca1d3d9b0cb6a2ef1264eb0f59524


TL;DR:V8 的 TurboFan 目前将 Map.has() 调用优化为 C++ 世界中的本机方法调用,但没有优化 Set.has() 调用。

不,为什么 Map.has 比 Set.has 快得多?

这也很有趣,因为它们必须使用相同的哈希表内部实现。

答案深入探讨如何TurboFan,V8的JIT编译器,做了优化。它利用节点海概念,你可以认为它是 AST 优化。 V8 通过用更快的表示替换节点海中的一些子树来进行优化(减少)。减少的最简单的例子是替换a = 1 + 2 to a = 3.

其超强功能之一是它可以用对底层 C++ 实现的调用来替换一些 JS 方法调用,以消除开销。请参阅官方幻灯片,尤其是其中的几页这个链接 https://docs.google.com/presentation/d/1sOEF4MlF7LeO7uq-uThJSulJlTh--wgLeaVibsbb3tc/edit#slide=id.g5499b9c42_089查看其功能的示例。

然后,查看实际减少发生的代码。

In js-call-reducer.cc https://github.com/v8/v8/blob/65d9c441dfad3d06d5a2cf2857a71e2388e10d6f/src/compiler/js-call-reducer.cc#L7223 of V8, JSCall of Map.has将被本机函数调用替换:

Reduction JSCallReducer::ReduceMapPrototypeHas(Node* node) {
  ...(reading current nodes)...

  Node* table = effect = graph()->NewNode(
      simplified()->LoadField(AccessBuilder::ForJSCollectionTable()), receiver,
      effect, control);

  Node* index = effect = graph()->NewNode(
      simplified()->FindOrderedHashMapEntry(), table, key, effect, control);

  Node* value = graph()->NewNode(simplified()->NumberEqual(), index,
                                 jsgraph()->MinusOneConstant());
  value = graph()->NewNode(simplified()->BooleanNot(), value);

  ReplaceWithValue(node, value, effect, control);
  return Replace(value);
}

(FindOrderedHashMapEntryFindOrderedHashTableEntry实际上查找哈希表的系列方法。查看源代码来自here http://%20https://github.com/v8/v8/blob/65d9c441dfad3d06d5a2cf2857a71e2388e10d6f/src/builtins/builtins-collections-gen.cc#L2403.)

But 没有ReduceSetPrototypeHas method,所以没有进行这样的优化Set.has。这就是为什么Set.has()慢于Map.has().

我确认本地构建的 V8 替换为以下代码可以使Set.has and Map.has基准测试结果几乎相同。

Reduction JSCallReducer::ReduceMapPrototypeHas(Node* node) {
  return NoChange();
}

我不确定是否Set.has是否应该优化,因为 V8 应该优化现实世界的应用,不适用于微基准测试结果。 (我也不知道添加新的减少量的缺点是什么以及有多大。)

(我不知道为什么升级 Node 6.2.0 -> 9.4.0Set.has()慢 3 倍。)

See https://v8.dev/docs/turbofan https://v8.dev/docs/turbofan了解 TurboFan 内部结构的更多资源。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JavaScript:为什么map.has比set.has和array.indexOf快这么多? 的相关文章

随机推荐

  • 如何检查groovy脚本的编译错误[重复]

    这个问题在这里已经有答案了 我们可以使用下面的代码在运行时创建并运行 groovyscript import groovy lang GroovyClassLoader import groovy lang GroovyObject imp
  • 如何将数据传递到 MSBuild 任务的 ITaskItem 属性?

    我有一个自定义任务 我在其中使用MSBuild 效果很好 以前 我有一些属性接受一些string数据 有人建议我应该将它们更改为ITaskItem的 这样 如果我有空间 就不会有问题 以前的代码 public class Compresso
  • 使用 facebook-android-sdk 4 未触发登录回调

    我有一个活动供用户使用 Facebook 登录 我使用 facebook android sdk v4 0 0 但是当用户点击登录按钮时 不会触发登录回调 显示进度条后 自动开始之前的活动 日志上不显示任何错误 而不是触发登录回调 在注册活
  • WCF 如何启用元数据?

    我正在尝试让我的 svc 文件在 IIS 下工作 在我的项目中 当我按 F5 时 svc 就开始工作了 所以我知道一切都好 对吗 IIS 除外 我正在 Windows XP Pro 计算机上工作 并在 IIS 中添加了一个虚拟目录 这是我的
  • Android MapView 带有滑动菜单遮挡菜单

    我在使用此滑动菜单的活动中有一个 android 地图 api v2 的地图视图https github com iPaulPro SlidingMenu https github com iPaulPro SlidingMenu 除了在地
  • WSO2 ESB - 用 Base64 写入文件

    我有一个代理 它接受包含 Base64 编码文件的 XML 文件 例如 XML 如下所示
  • Async Servlet - 首选实现

    最近 在研究异步处理时Servlets 我至少遇到了三种实现方法 使用这种方法的一些功能 问题是 哪一个是最好的 也许其中一些方法不推荐 也许还有另一种方法比下面提到的所有方法更好 找到的方法 Using AsyncContext star
  • Flutter安装在windows环境变量中

    我在尝试首先在桌面上安装 flutter 时遇到问题 出现以下错误 不被识别为内部或外部命令可操作程序或批处理文件 然后我打开系统环境变量并将 flutter 添加到用户变量路径 并将所有 flutter git system32 添加到系
  • silverlight/wcf ria 中的部分实体加载和管理

    我有一个 Silverlight 4 应用程序 它使用 WCF RIA 服务从数据库中提取实体 这些数据对象相当简单 只有几个字段 但其中一个字段包含任意大小的二进制数据 应用程序基本上需要在用户登录后尽快访问这些数据 以在列表中显示 启用
  • X509 主题备用名称 (subjectAltName) IP 地址字段

    X509v3 可以包含IP地址字段在subject Alternative Name扩大 作为验证服务器身份的应用程序 IP地址字段应该如何验证 DNS 名称和 IP 地址是否都存在 是否存在对其中一种的偏好 有什么用dirName fie
  • 如何访问应用程序特定文件夹并使用它来备份或某些应用程序特定数据?迅速

    我想创建一个应用程序 其中某些类型的数据将同步到应用程序特定文件夹中的谷歌驱动器 并且可以进一步访问它以检索数据并填充到应用程序中 如果不知何故用户的手机丢失并且用户使用另一部手机 并且当用户登录同一谷歌帐户时 应该获取该数据 My pro
  • Android SoftKeyboard 如何创建自己的建议

    我正在开发一个基于软键盘示例的键盘 我想知道如何创建自己的建议 我在 Candidate View Class 中看到 setSuggestion 方法 但在该方法的参数中 我看到字符串 建议 列表被传递到此方法中 我的问题是 我是否必须为
  • wxPython 框架上的背景图像

    MMGP 已回答 但不会让我相信他是正确的 所以我至少会在这里提到他 我终于相信了他 8 他的链接讨论 http wiki wxpython org DoubleBufferedDrawingon Double Buffering 提供了经
  • ":eq()" 和 .eq() 之间的区别

    我最近开始学习jQuery 考虑到以下html结构 我想知道选择器之间的基本区别是什么 ul gt li eq 2 and ul gt li eq 2 ul li one li li two li li three li li four l
  • Pandas DataFrame-查找列的索引值

    我有一个 DataFrame 其中包含 ID 名称 规格 时间等列 我打开它们的文件路径 mc pd read csv C data csv sep header 0 dtype str 当我检查我的列值时 使用 mc coulumns v
  • 使用 svcutil 为客户端代理生成 xsd 文件

    我正在尝试使用 Svcutil 导出元数据以从本地托管服务生成代理 我不想进入 Visual Studio 并单击 添加服务引用 因为这是我的学习练习 我使用 svcutil 如下 Svcutil d c temp t 元数据http lo
  • 如何从tomcat webapp中的context.xml文件获取资源?

    这是我的上下文 xml file
  • 打开 Javascript 文件时 Visual Studio 2015 崩溃

    每次我使用 Visual Studio 2015 Pro RTM 打开 Javascript 文件时 它都会崩溃并重新启动 没有错误消息 我进行了修复 但尚未尝试卸载并重新安装 还有其他人遇到这个问题吗 好吧 我终于想通了 它确实与 ref
  • MouseDown 在网格中不起作用(仅适用于网格中的按钮)

    我的 MouseDown 事件有问题 我的应用程序看起来像这样 我有网格 我在后面的代码中添加按钮
  • JavaScript:为什么map.has比set.has和array.indexOf快这么多?

    我遇到了以下基准 https jsperf com array includes and find methods vs set has https jsperf com array includes and find methods vs