Guava ImmutableMap的访问速度明显低于HashMap。

2022-09-01 04:02:07

在对一些高吞吐量数据结构进行内存基准测试时,我意识到我只需要一点点重构就可以使用。ImmutableMap

我以为这将是一个改进,我把它扔进了混合中,并惊讶地发现它不仅比 慢,在单线程环境中,它似乎总是比慢!HashMapConcurrentHashMap

您可以看到完整的基准测试

测试的肉非常简单,需要多长时间才能获得地图中可能存在的大量随机字符串。

public static void timeAccess(Map<String,String> map) {
    Random rnd = new Random(seed);
    int foundCount = 0;

    long start = System.nanoTime();

    for(int i = 0; i < loop; i++) {
        String s = map.get(RndString.build(rnd));
        if(s != null)
            foundCount++;
    }

    long stop = System.nanoTime() - start;

    System.out.println("Found "+foundCount+" strings out of "+loop+" attempts - "+
        String.format("%.2f",100.0*foundCount/loop)+" success rate.");
    System.out.println(map.getClass().getSimpleName()+" took "+
        String.format("%.4f", stop/1_000_000_000.0)+" seconds.");
    System.out.println();
}

并且对包含相同值的 a、a 和 an 运行此项,在使用时始终显示出明显的减速 - 通常慢 15% 以上。映射越稀疏(即返回 null 的频率越高),差异就越大。下面是示例运行的结果:HashMapConcurrentHashMapImmutableMapImmutableMapmap.get()

Found 35312152 strings out of 100000000 attempts - 35.31 success rate.
HashMap took 29.4538 seconds.

Found 35312152 strings out of 100000000 attempts - 35.31 success rate.
ConcurrentHashMap took 32.1465 seconds.

Found 35312152 strings out of 100000000 attempts - 35.31 success rate.
RegularImmutableMap took 37.9709 seconds.

这是一个有案可稽/预期的问题吗?番石榴文档表明内存效率更高,但没有提到速度。对于这种程度的减速,我倾向于处理内存成本,并避免当速度是一个问题时(什么时候不是问题?!)。我错过了什么吗?Immutable***Immutable***

请参见:https://groups.google.com/forum/?fromgroups=#!topic/guava-discuss/I7yPpa5Hlpg


答案 1

正如Louis Wasserman所说,没有针对具有慢速方法的对象进行优化。我认为主要区别在于:ImmutableMapequals

哈希地图

if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
    return e.value;

ImmtubleMap

if (key.equals(candidateKey)) {
    return entry.getValue();

如您所见,要检查冲突,请首先检查哈希值。这允许快速拒绝具有不同哈希的值。由于在其方法中没有进行此检查,因此速度更快。 不使用此优化,因为当已优化时,它会使测试速度变慢。HashMapStringequalsHashMapImmutableMapequals


答案 2

一些可能的原因:

  1. 这取决于你对RndString.build()的实现吗?

  2. 看看这两个地图的get()实现:com.google.common.collect.RegularImmutableMap.get(Object) java.util.HashMap.getEntry(Object) java.util.HashMap试图首先与“==”进行比较。RegularImmutableMap 则不然。这可能会加速

  3. 不同的负载系数是否会导致这种情况?也许 RegularImmutableMap 需要更多的迭代才能找到正确的条目。


推荐