V S*_*S X 16 javascript performance dictionary object set
我试图探索 JavaScript与普通按键访问Object相比如何执行。我在JSBEN.CH上运行了以下 3 段代码。MapSet
对象
const object = {};
for (let i = 0; i < 10000; ++i) {
object[`key_${i}`] = 1;
}
let result = 0;
for (let i = 0; i < 10000; ++i) {
result += object[`key_${i}`];
}
Run Code Online (Sandbox Code Playgroud)
地图
const map = new Map();
for (let i = 0; i < 10000; ++i) {
map.set(`key_${i}`, 1);
}
let result = 0;
for (let i = 0; i < 10000; ++i) {
result += map.get(`key_${i}`);
}
Run Code Online (Sandbox Code Playgroud)
套
const set = new Set();
for (let i = 0; i < 10000; ++i) {
set.add(`key_${i}`);
}
let result = 0;
for (let i = 0; i < 10000; ++i) {
result += set.has(`key_${i}`);
}
Run Code Online (Sandbox Code Playgroud)
正如您可以检查测试链接一样,Map似乎Set执行几乎相似,但Objects每次都慢得多。有人可以解释一下性能比基本密钥访问操作Objects差的原因是什么吗?MapSet
编辑 1:仅将键设置为 on也Object比/慢。MapSet
Jon*_*lms 32
仅查看相对数字总是危险的,这里有一些绝对数字,在 Intel 8350U 上的 NodeJS v14.14.0 上运行:
| 迭代 | 对象写入 | 对象读取 | 地图写入 | 地图读取 |
|---|---|---|---|---|
| 100 | 0毫秒 | 0毫秒 | 0毫秒 | 0毫秒 |
| 1.000 | 3毫秒 | 1毫秒 | 0毫秒 | 0毫秒 |
| 10,000 | 7毫秒 | 4毫秒 | 8毫秒 | 1毫秒 |
| 1.000.000 | 1222毫秒 | 527毫秒 | 632毫秒 | 542毫秒 |
正如我们所看到的,对于 10,000 次迭代,在上面的运行中,对象和地图之间的差异为 1 毫秒,并且由于这是时间测量的准确性,因此我们无法真正从该测试中得出任何结论。结果绝对是随机的。
对于 100 万次迭代,我们可以看到 Map 写入相对于 Object 写入的明显优势,读取性能非常相似。现在,如果我们看一下绝对数字,这仍然是100 万次写入/秒。因此,尽管对象写入速度慢很多,但这不太可能成为应用程序的瓶颈。
为了得到准确的解释,人们必须分析引擎执行的所有步骤。为此,您可以运行node --print-code并分析运行的字节码。我没有时间这样做,但这里有一些观察结果:
如果对象是用Object.create(null)(没有原型)构造的,则性能大致相同,因此原型查找根本不会影响性能。
在第 20 次迭代之后,V8 选择 的内部表示,dictionary_map因此object这基本上是一个哈希图与另一个哈希图竞争(可以运行node --allow-natives-syntax然后使用%DebugPrint(object)来获取内部表示)。
作为参考,以下是用于运行基准测试的代码:
function benchmark(TIMES) {
console.log("BENCHMARK ", TIMES);
const object = Object.create(null);
let start = Date.now();
for (let i = 0; i < TIMES; ++i) {
object[`key_${i}`] = 1;
}
console.log("Object write took", Date.now() - start);
start = Date.now();
let result = 0;
for (let i = 0; i < TIMES; ++i) {
result += object[`key_${i}`];
}
console.log("Object read took", Date.now() - start);
start = Date.now();
const map = new Map();
for (let i = 0; i < TIMES; ++i) {
map.set(`key_${i}`, 1);
}
console.log("Map write took", Date.now() - start);
start = Date.now();
result = 0;
for (let i = 0; i < TIMES; ++i) {
result += map.get(`key_${i}`);
}
console.log("Map read took", Date.now() - start);
}
benchmark(100);
benchmark(1_000);
benchmark(10_000);
benchmark(1_000_000);Run Code Online (Sandbox Code Playgroud)
总结:
| 归档时间: |
|
| 查看次数: |
15973 次 |
| 最近记录: |