ImmutableMap是大量键/对象的次优选择/

时间:2015-02-01 22:28:42

标签: java collections hashmap guava

我正在与同事进行一些测试,我们从数据库中提取数据(大约350,000条记录),将每条记录转换为对象和关键对象,然后将它们填充到ImmutableMap.Builder中。

当我们调用build()方法时,它花了很长时间,可能是由于ImmutableMap(dupe keys,nulls等)附带的所有数据完整性检查。公平地说,我们也试图使用一个hashmap,这需要一段时间但不像ImmutableMap那么长。我们最终决定只使用ConcurrentHashMap,当迭代记录时,我们填充了9个线程,并将其包装在一个不可修改的映射中。表现很好。

我在文档中注意到它读取的ImutableMap没有针对" equals()"进行优化。操作。作为一个顽固的不可变因素,我希望ImmutableMap适用于大数据量,但我感觉它并不意味着它。这个假设是对的吗?它是否仅针对中小型数据集进行了优化?我需要通过" copyOf()"来调用隐藏的实现吗?还是什么?

2 个答案:

答案 0 :(得分:1)

我的经验是,Java内置的Collection类都没有真正针对大量的性能进行优化。例如,一旦hashCode用作数组中的索引,HashMap就使用简单迭代,并通过equals将密钥与具有相同散列的每个项进行比较。如果您要在地图中存储数百万个项目,那么您需要一个设计良好的哈希和大容量。这些类旨在尽可能通用和安全。

因此,如果您希望坚持使用标准Java HashMap,请尝试性能优化:

  1. 确保您的哈希函数尽可能接近均匀分布。许多域都有偏差值,您的哈希需要考虑到这一点。
  2. 如果您有大量数据,HashMap将会多次展开。理想情况下,将初始容量设置为尽可能接近最终值。
  3. 确保您的equals实施尽可能高效。
  4. 如果您知道(例如)您的密钥是整数,则可以应用大量的性能优化,例如在应用散列后使用某种形式的btree并使用==而不是{{1 }}

    所以简单的答案是,我相信你需要编写自己的集合来获得你想要的性能,或者使用一个更优化的实现。

答案 1 :(得分:1)

我猜你的key.equals()是一种耗时的方法。

key.equals()ImmutableMap.build()中将被称为更多次而不是HashMap.put()(在循环中)。 key.hashCode()被称为同一时间HashMap.put()ImmutableMap.build()。因此,如果key.equals()花费很长时间,则整个持续时间可能会有很大差异。

key.equals()期间,

HashMap.put()会被调用几次(好的哈希算法导致一些冲突)。 如果是ImmutableMap.build(),则key.equals()会多次调用checkNoConflictInBucket()key.equals()的O(n)。

构建地图后,两种类型的地图在访问时不应有太大差异,因为两者都是基于散列的。

样品: 有10000个随机字符串作为键。 HashMap.put()来电  String.equals() 2次,而ImmutableMap.build()则拨打3000次。