番石榴ImmutableSet.contains的表现

时间:2012-09-24 21:53:17

标签: set guava immutability caliper

Guava的ImmutableSet似乎在关于contains的基准测试中表现不佳。对于某些尺寸,它甚至比List慢得多:

  size            benchmark         ns linear runtime
100000         ListContains  110279.54 ==
100000          SetContains       7.15 =
100000 ImmutableSetContains   76716.47 =
200000         ListContains  275367.66 =====
200000          SetContains       7.34 =
200000 ImmutableSetContains  322185.50 ======
500000         ListContains  935210.10 ====================
500000          SetContains       7.79 =
500000 ImmutableSetContains 1382765.76 ==============================

基本上,我用几千个负整数填充一个集合,并且测试包含非负数整数。代码很简单,但是在一个小的文本区域粘贴有点太长了,所以请看here

我想知道这里发生了什么。可能,我遇到了一些堕落的情况,尽管我显然没有尝试过。或许我刚刚吹了基准。否则,我想知道它是否可以而且应该修复。


解决方案是通过replacing

更改拖尾函数
hashCode ^= (hashCode >>> 20) ^ (hashCode >>> 12);
return hashCode ^ (hashCode >>> 7) ^ (hashCode >>> 4);

通过

return C2 * Integer.rotateLeft(hashCode * C1, 15);

这需要大约相同的时间并且可能有一些缺点,但通过很好地散布哈希来解决当前的问题。

1 个答案:

答案 0 :(得分:6)

解释实际上非常简单。想象一下,对于某些M = {0, 1, ..., N-1},整数位于集N中,这是2的幂。哈希也是如此,因为Integer.hashCode的定义方式。哈希通过与this one相同的函数smear进行处理,以便在一些常见情况下最小化最低位的冲突。

分配了一个大小为2*N的表,并将M的成员放入其中。由于smear仅涉及右移,因此会将M映射到自身,这意味着表的连续范围会被填充。因此,假设使用了表格左半部分的所有插槽而另一半未使用。

contains(o)被调用时,搜索从一个位置开始,该位置由o.hashCode()确定。如果找到o,结果为true,如果空广告位被点击,则结果为false。否则,搜索进入另一个时隙。为了最大限度地减少缓存未命中,linear probing被使用。

当我们不幸在第一个使用过的插槽中开始搜索时,必须遍历所有这些,这意味着N个步骤。从随机位置开始意味着N/4平均步数。

我的基准测试中发生的情况并不完全如上,但其性能不佳的原因是相同的。将大小调整为2会使问题变得更糟。