我正在与同事进行一些测试,我们从数据库中提取数据(大约350,000条记录),将每条记录转换为对象和关键对象,然后将它们填充到ImmutableMap.Builder中。
当我们调用build()方法时,它花了很长时间,可能是由于ImmutableMap(dupe keys,nulls等)附带的所有数据完整性检查。公平地说,我们也试图使用一个hashmap,这需要一段时间但不像ImmutableMap那么长。我们最终决定只使用ConcurrentHashMap,当迭代记录时,我们填充了9个线程,并将其包装在一个不可修改的映射中。表现很好。
我在文档中注意到它读取的ImutableMap没有针对" equals()"进行优化。操作。作为一个顽固的不可变因素,我希望ImmutableMap适用于大数据量,但我感觉它并不意味着它。这个假设是对的吗?它是否仅针对中小型数据集进行了优化?我需要通过" copyOf()"来调用隐藏的实现吗?还是什么?
答案 0 :(得分:1)
我的经验是,Java内置的Collection
类都没有真正针对大量的性能进行优化。例如,一旦hashCode用作数组中的索引,HashMap就使用简单迭代,并通过equals
将密钥与具有相同散列的每个项进行比较。如果您要在地图中存储数百万个项目,那么您需要一个设计良好的哈希和大容量。这些类旨在尽可能通用和安全。
因此,如果您希望坚持使用标准Java HashMap,请尝试性能优化:
HashMap
将会多次展开。理想情况下,将初始容量设置为尽可能接近最终值。equals
实施尽可能高效。如果您知道(例如)您的密钥是整数,则可以应用大量的性能优化,例如在应用散列后使用某种形式的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次。