javascript - 为什么这个 JavaScript 代码在 Node.js 优化后运行速度变慢了
问题描述
当我遇到一个有趣的问题时,我正在使用 JavaScript 和Node.js创建一个ICPC问题的解决方案:在某些情况下,我的程序在同一数据集上运行速度会慢两倍。
我将其剥离,直到得到演示该行为的最小示例:
function solve(arr) {
const total = arr.reduce((a, c) => a + c, 0);
const count = arr.length;
for (let i = 0; i < total; i++) {
for (let j = 0; j < count; j++) {
// calculate some stuff
}
}
}
for (let i = 0; i < 10; i++) {
// generate some sample data (array of 5000 random numbers 1-10)
const data = [];
for (let i = 0; i < 5000; i++) {
data.push(Math.floor(Math.random() * 10) + 1);
}
const start = new Date();
solve(data); // run solve on the data
console.log(`${i + 1}: ${new Date() - start}ms`);
}
这是node --trace-opt code.js
使用Node
v10.15.1 运行的输出:
[marking 0x005062b82521 <JSFunction solve (sfi = 000001DA56AD8CD9)> for optimized recompilation, reason: small function, ICs with typeinfo: 5/7 (71%), generic ICs: 0/7 (0%)]
[compiling method 0x005062b82521 <JSFunction solve (sfi = 000001DA56AD8CD9)> using TurboFan OSR]
[optimizing 0x005062b82521 <JSFunction solve (sfi = 000001DA56AD8CD9)> - took 1.453, 0.702, 0.082 ms]
1: 86ms
[marking 0x005062b82581 <JSFunction (sfi = 000001DA56AD8BD9)> for optimized recompilation, reason: hot and stable, ICs with typeinfo: 22/23 (95%), generic ICs: 1/23 (4%)]
[compiling method 0x005062b82521 <JSFunction solve (sfi = 000001DA56AD8CD9)> using TurboFan]
[optimizing 0x005062b82521 <JSFunction solve (sfi = 000001DA56AD8CD9)> - took 0.159, 0.632, 0.096 ms]
2: 82ms
3: 80ms
[compiling method 0x005062b82581 <JSFunction (sfi = 000001DA56AD8BD9)> using TurboFan OSR]
[optimizing 0x005062b82581 <JSFunction (sfi = 000001DA56AD8BD9)> - took 0.592, 2.312, 0.154 ms]
4: 245ms
5: 243ms
6: 236ms
7: 237ms
8: 240ms
9: 246ms
10: 239ms
在前三个迭代期间,运行时间约为 80 毫秒,但就在第四次迭代Node
重新编译和优化方法之前,从那时起,代码运行速度大约慢了 3 倍。
通常什么Node
时候运行时分析、重新编译和优化一切运行得更快。
谁能解释为什么Node
在这种情况下优化会使事情变得更糟?
请注意,如果将示例代码更改为total
通过迭代而不是使用reduce
优化来计算,则可以按预期提高性能(运行时间下降到 60 毫秒左右):
let total = 0;
for (let v of arr) total += v;
解决方案
我提交了一份错误报告,并从Chromium开发人员那里得到了以下回复:
一些数组内建函数使用分支提示进行循环边界检查,导致内联内建函数之后的所有代码都成为延迟代码。这对性能不利。
所以事实证明这是TurboFan
编译器的一个已知问题,并且已经创建了一个修复程序并且目前正在测试:
此 CL 将微基准上的提示从链接的错误中删除了 3 倍,从而大大改进了代码调度。
推荐阅读
- html - 内容内的链接,背景从左到右填充,然后从右到左填充,这样看起来盒子正在向右滑动
- python - 删除每组中最后一个子组对应的行
- javascript - 如何在 React JS 中获取卡片的 href 和 id 的动态值
- xamarin - System.IO.FileLoadException:无法加载文件或程序集“Mono.Cecil.Pdb”
- automation - 在 Automation Anywhere 中显示循环计数器
- javascript - JavaScript 检查对象是否是具有特定值的数组
- vba - 在excel公式中添加$?
- php - 使用 AWS SES 发送批量电子邮件
- angularjs - 如何将 data-plugin="timepicker" 值传递给 angularJS 中的控制器
- function - 使用一个附加函数在 FORTRAN 中未定义的引用