【发布时间】:2014-06-22 21:26:26
【问题描述】:
这是一个奇怪的案例,最近在分析我一直在研究的一个专业集合时出现。
该集合几乎只有两个数组,一个是 int[] 键数组,另一个是 Object[] 值数组,具有提供快速查找的哈希函数。这一切都很好,但我已经开始分析代码并且得到了一些奇怪的结果;对于分析,我决定用老式的方式来做,抓住System.currentTimeMillis(),一遍又一遍地运行测试,然后检查已经过去了多少时间,就像这样:
long sTime = System.currentTimeMillis();
for (int index : indices)
foo.remove(index);
long took = System.currentTimeMillis() - sTime;
在我的测试中,foo 准备了 200,000 个条目,并预先生成了 indices 列表,我将删除该列表。我使用循环重置并运行测试一千次,并将took 添加到运行总数中。
现在,对于命令,与其他数据类型相比,我得到了非常好的结果,除了我的remove(int) 方法。但是,我一直在努力找出原因,因为我的删除方法与我的 get(int) 方法相同(显然是删除除外),如图所示:
public Object get(int key) {
int i = getIndex(key); // Hashes key and locates it
return (i >= 0) ? this.values[i] : null;
}
public Object remove(int key) {
int i = getIndex(key); // Does exactly the same as above
if (i >= 0) {
--this.size;
++this.modifications; // For concurrent access behaviour
this.keys[i] = 0; // Zero indicates null entry
Object old = this.values[i];
this.values[i] = null;
return old;
}
return null;
}
虽然我预计删除需要更长的时间,但它们的执行时间是 get(int) 的 5 倍以上。但是,如果我注释掉 this.keys[i] = 0 行,那么性能将与 get(int) 几乎相同。
我是否正确地观察到这是给我的int[] 数组赋值的问题?我尝试注释掉所有 this.values 操作并体验同样的缓慢时间,但是在注释掉 this.keys[i] = 0 的同时留下 this.values 始终可以解决问题;我完全不知道发生了什么事,有什么办法可以解决吗?
考虑到删除相对较少,性能仍然不错,但在 int[] 中设置值似乎会产生如此大的影响似乎很奇怪,所以我很想知道为什么。
【问题讨论】:
-
我认为您需要提供一个完全可重现的基准,最好利用像 Caliper 这样的基准库来消除最常见的缺陷。
-
随机猜测:当您将
keys[]元素归零时,getIndex()在寻找密钥时还有更多工作要做。无论如何,请提供更多背景信息 - 问题可能出在您的基准测试中,也可能出在getIndex()或任何其他未显示给我们的地方。 -
嗯,我希望避免发布太多内容;我的测试设置为仅对已知存在的键调用
remove(int),并且getIndex(int)在恒定时间内返回。此外,我确定不是getIndex(int)有问题,因为注释掉this.keys[i] = 0会显着改变结果(1200ms 到 200ms,与get(int)相同),我就是不明白为什么。 -
我已经尝试创建一个 JBenchX 测试用例,并在使用和不使用
this.keys[i] = 0的情况下运行了几次,并且得到了类似的结果。启用语句的测试大约需要 214ns,而没有启用语句的测试是 56ns。禁用this.keys[i] = 0时,我将其替换为this.values[i] = DELETED(标记对象)和相应的检查,但不知何故它快了近四倍。 -
查找读取
keys[]的代码片段。似乎归零会改变执行路径。尝试使用-Xint选项运行JVM 以排除JIT 优化因素。remove还会慢 5 倍吗?
标签: java arrays performance