Guava ImmutableMap的访问速度明显慢于HashMap

时间:2013-04-02 05:40:49

标签: java performance hashmap benchmarking guava

在研究某些高吞吐量数据结构的内存基准测试时,我意识到我只能使用ImmutableMap进行一些重构。

认为这将是一种改进,我把它扔进了混合物并且惊讶地发现它不仅比HashMap慢,在单线程环境中它似乎始终比{{慢一点慢1}}!

您可以在此处查看完整的基准:https://bitbucket.org/snippets/dimo414/89K7G

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

ConcurrentHashMap

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(); } HashMapConcurrentHashMap执行此操作时,所有内容都包含相同的值,在使用ImmutableMap时始终显示出显着的减速 - 通常向上减慢15%。地图越稀疏(即,ImmutableMap返回的空值越多),视差越大。以下是样本运行的结果:

map.get()

这是一个记录/预期的问题吗? Guava Docs表示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***(何时不是?!)。我错过了什么吗?

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

2 个答案:

答案 0 :(得分:16)

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

HashMap

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

ImmtubleMap

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

如您所见,要检查碰撞,HashMap首先检查哈希值。这允许快速拒绝具有不同散列的值。由于String未在equals方法中进行此检查,因此HashMap更快。 ImmutableMap不使用此优化,因为当equals已经优化时,它会使测试变慢。

答案 1 :(得分:0)

一些可能的原因:

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

  2. 看看两个地图的get()实现: com.google.common.collect.RegularImmutableMap.get(对象) java.util.HashMap.getEntry(对象) java.util.HashMap首先尝试与“==”进行比较。 RegularImmutableMap没有。这可能会加快

  3. 可能有不同的负载因素吗?也许RegularImmutableMap需要更多的迭代才能找到正确的条目。