node.js - 为什么 Node 比 Chrome 慢 10 倍?
问题描述
我正在 Chrome 和 Node.js 中运行我的Z80 模拟器。我在 Chrome 中的性能大约是在 Node.js 中的 10 倍。(100k Z80 指令在 Chrome 中需要 6 毫秒,在 Node 中需要 60 毫秒。)我已经运行了分析器:
% node --prof index.js
% node --prof-process isolate-0x108000000-25550-v8.log
它说 95% 的时间花在 C++ 上:
[Summary]:
ticks total nonlib name
103 3.8% 3.8% JavaScript
2604 95.2% 95.8% C++
6 0.2% 0.2% GC
17 0.6% Shared libraries
12 0.4% Unaccounted
C ++细分是:
[C++ entry points]:
ticks cpp total name
2127 98.3% 77.7% T __ZN2v88internal40Builtin_CallSitePrototypeGetPromiseIndexEiPmPNS0_7IsolateE
32 1.5% 1.2% T __ZN2v88internal21Builtin_HandleApiCallEiPmPNS0_7IsolateE
我已经追踪CallSitePrototypeGetPromiseIndex
到这个源文件。我没有在我的代码中使用承诺、、async
或。await
我的测试只是一个 100k 模拟 Z80 指令的紧密循环,没有 I/O 或任何东西。
我在网上找到了其他人使用该--prof
标志,但没有人在他们的结果中找到这一点。这是分析的副作用吗?我是否在循环中以某种方式触发了承诺?有什么理由 Node 应该比 Chrome 慢这么多?
详细信息:节点 v12.13.1,Chrome 79.0.3945.88。
解决方案
好的,这个令人惊讶的相似问题有一个很好的答案,Esailija 将我指向V8 源代码中的这一行。它将 switch 语句的优化限制在一定大小以下。我的模拟器做的第一件事是为操作码分配 256 个入口的开关。在我的测试中,我只通过了 0 (NOP),因此注释掉大量案例是安全的。事实证明,如果我注释掉 13 个案例,性能会提高 25 倍!如果我只注释掉 12 个案例,那么我会得到缓慢的性能。
上面 V8 源代码的链接很旧(2013 年),所以我试图找到现代的等价物。我没有找到硬性限制,但发现了几种在表查找和树(二进制搜索)查找(ia32,x86)之间做出决定的启发式方法。当我插入我的数字时,我并没有完全找到找到它的临界案例,所以我不确定这是实际原因,或者是否有其他优化没有在其他地方触发。
至于与 Chrome 的区别,他们决定优化开关的时间和方式可能存在一些细微差别。
我不确定这里最好的解决方案是什么,但显然我需要避免使用大的 switch 语句。我要么有一系列较小的 switch 语句,要么用一组函数替换整个东西。
更新:我使用了一系列函数,我的整个程序加速了 25 倍。
推荐阅读
- netty - 检测 micronaut netty 中的非阻塞线程
- eclipse - 从 MagicDraw 中的图表生成表格
- javascript - Node 和 Express 中未处理的 promise 错误
- r - 删除 R 上的差异值测量中的重复项
- sql - SQL Server:加入两个不同的查询
- docker - 如何在 Apple 芯片上运行 camunda
- gradle - 独立的 gradle 插件可以导出自定义任务类型吗?
- c# - 在 cshtml 文件中为 2 个按钮发送 2 个 recaptcha v3 令牌的问题
- salesforce - Salesforce 日期公式未显示正确结果
- javascript - 如何抵消“chart.js”条形图中的条形图例?