设置查找时间比对象慢?

时间:2016-05-26 15:08:27

标签: javascript performance

出于好奇,我决定在插入/添加和查找方面确认我认为Set实现比Object(在google chrome中运行)更快。我的结果有些令人困惑。

x = {};
y = new Set();

console.time('Insert into Object');
for (var i = 0; i < 1000000; i++) {
    x[i] = 0;
}
console.timeEnd('Insert into Object');

console.time('Insert into Set');
for (i = 0; i < 1000000; i++) {
    y.add(i);
}
console.timeEnd('Insert into Set');

var t = 0;

console.time('Retrieve from Object');
for (i = 0; i < 1000000; i++) {
    t = x[i];
}
console.timeEnd('Retrieve from Object');

console.time('Retrieve from Set');
for (i = 0; i < 1000000; i++) {
    t = y.has(i);
}
console.timeEnd('Retrieve from Set');

VM19742:9  Insert into Object: 1341.777ms
VM19742:15 Insert into Set: 1473.025ms
VM19742:23 Retrieve from Object: 1469.717ms
VM19742:29 Retrieve from Set: 1666.430ms

正如您所看到的,该集合的表现略差于Object。这让我感到困惑,因为我认为底层实现与对象完全相同,没有存储值的额外开销。有没有人对这是为什么有任何额外的见解?

2 个答案:

答案 0 :(得分:3)

为了解决您的问题,为什么您认为存储值可能比检查现有值以查看是否需要存储它更慢?

为了完成,我修改了你的代码以包含数组。

x = {};
y = new Set();
z = [];

console.time('Insert into Object');
for (var i = 0; i < 1000000; i++) {
    x[i] = 0;
}
console.timeEnd('Insert into Object');

console.time('Insert into Set');
for (i = 0; i < 1000000; i++) {
    y.add(i);
}
console.timeEnd('Insert into Set');

console.time('Insert into Array');
for (i = 0; i < 1000000; i++) {
    z[i] = 0;
}
console.timeEnd('Insert into Array');

var t = 0;

console.time('Retrieve from Object');
for (i = 0; i < 1000000; i++) {
    t = x[i];
}
console.timeEnd('Retrieve from Object');

console.time('Retrieve from Set');
for (i = 0; i < 1000000; i++) {
    t = y.has(i);
}
console.timeEnd('Retrieve from Set');

console.time('Retrieve from Array');
for (i = 0; i < 1000000; i++) {
    t = z[i];
}
console.timeEnd('Retrieve from Array');

console.log(t);

通常,人们会期望存储到对象中是O(1)时间复杂度,而检查集合中的现有值应该不超过 O(n)(其中n是数字)对于集合中的项目,所以我们应该期望随着集合变大,集合可能会变慢。这种性能甚至可能依赖于实现,即不同的javascript运行时可能表现不同。

事实上,这正是我们所看到的:(在我的机器上运行)

(您的代码)

Insert into Object: 67.558ms
Insert into Set: 259.841ms
Insert into Array: 64.297ms
Retrieve from Object: 19.337ms
Retrieve from Set: 149.968ms
Retrieve from Array: 3.981ms

但是,如果我们更改您的插入测试以不断重新添加相同的值...

我们看到了:

Insert into Object: 19.103ms
Insert into Set: 40.645ms
Insert into Array: 16.384ms
Retrieve from Object: 40.116ms
Retrieve from Set: 30.672ms
Retrieve from Array: 70.050ms

这告诉我们一些事情。首先,不同类型对集合的大小不同。其次,从数组或对象中检索不存在的键比检查相同值的集合要慢(至少在此特定实现上)。

最后一点

我认为重要的是要注意,我们正在讨论在百万次迭代(或大约一秒半)的情况下,相对于一秒钟的事情的相对表现。测试)。这已经非常快了。对于那些将来阅读本文的人,请记住选择语义上您想要的数据结构。从性能角度来看,这三者中的任何一个都是非常好的选择。选择使您的程序最容易理解的那个。

答案 1 :(得分:0)

测试用例有点缺陷。

  1. 由于整数键的使用一致,因此该对象可能会针对数组进行优化。
  2. 对象中的查找将更准确地使用x.hasOwnProperty(key)x[key]!==undefined