繁体   English   中英

保证密钥唯一时 HashMap 的性能

[英]Performance for HashMap when Key is Guaranteed Unique

如果保证我希望使用的键是唯一的(或者至少可以假设键是唯一的),使用“香草” ConcurrentHashMap是否提供最佳性能,或者散列 function 或 put 方法是否需要进行修改以避免不必要的散列?

此外,数字键是否比非数字键(例如具有适当散列函数的字符串或 POJO)具有任何性能优势?

正如评论中已经提到的,如果您不需要线程安全方面,请不要使用ConcurrentHashMap

如果您想要绝对最佳的性能,请考虑实习您的密钥并使用IdentityHashMap 这避免了计算 object 的 hash (并且,如评论中所述,否定了对equals进行评估的需要),而是假设引用本身是 Z0800FC577294C34E94528AD28394。

请注意,您必须确保相同密钥的两个实例是相同的 object(例如,您必须确保引用相等,而不仅仅是 object 相等)。 实习你所有的钥匙是实现这一目标的一种方法。

实施说明:这是一个简单的线性探头 hash 表,如 Sedgewick 和 Knuth 的文本中所述。 该数组交替保存键和值。 (与使用单独的 arrays 相比,这对于大型表具有更好的局部性。)对于许多 JRE 实现和操作混合,此 class 将产生比 HashMap 更好的性能(使用链而不是线性探测)。

如果您知道所有密钥,也许您还可以考虑完美散列 还是 map 到一个简单的数组结构?

ConcurrentHashMap 是 HashMap 实现中最昂贵的,这是因为它是线程安全的。

所有地图都必须有唯一的键,所以这是给定的。

如果您使用支持 TLongHashMap 等基元的集合,则使用数字具有性能优势,但是您可以使用自定义 hash Z1D78DC8ED51214E518B5114AE24490 更快地 go。

来自http://vanillajava.blogspot.com/2011/07/low-gc-in-java-using-primitives.html

Test                                    Performance Memory used
Use Integer wrappers and HashMap        71 - 134 (ns)   53 MB/sec
Use int primitives and HashMap          45 - 76 (ns)    36 MB/sec
Use int primitives and FastMap          58 - 93 (ns)    28 MB/sec
Use int primitives and TIntIntHashMap   18 - 28 (ns)    nonimal
Use int primitives and simple hash map   6 - 9 (ns)     nonimal 

如果保证我希望使用的键是唯一的(或者至少可以假设键是唯一的),那么使用“香草”ConcurrentHashMap 是否提供最佳性能,

如果Map是潜在的并发瓶颈,您通常会使用ConcurrentHashMap 如果您的应用程序是单线程的或没有争用,则ConcurrentHashMapHashMap慢。

或者是否需要修改散列 function 或 put 方法以避免不必要的散列?

hash function 对 hash 表的每个“探针”进行一次评估; 例如,每次getput操作一次。 可以通过缓存结果来降低 hash function 的成本,但这会花费您每个密钥 object 额外 4 字节的存储空间。 缓存是否值得优化取决于:

  • 与应用程序的 rest 相比,散列的相对成本是多少,以及
  • 实际使用缓存值的hashCode()调用比例。

这两个因素都是高度应用特定的。

(顺便说一句,使用身份哈希码作为 hash 值的长期成本也是额外的 4 个字节的存储空间。)

此外,数字键是否比非数字键(例如具有适当散列函数的字符串或 POJO)具有任何性能优势?

hash function 在数字情况下可能更便宜,但是否值得取决于使用数字键是否存在特定于应用程序的缺点。 而且,如上所述,相对成本是应用程序的具体情况。 例如, String.hashCode()的成本与被散列的字符串的长度成正比。

Java 的 HashMap 最终由一个Entry<K,V>数组支持,其中 K 的哈希码用于确定存储 Entry 的数组中的槽。

使用的数组的大小(通常从 16 开始)远小于可能的哈希码数量(2^32 ~= 40 亿),因此即使哈希码是唯一的,该数组也必然会发生冲突。

只要您的 hashcode() 方法速度快,用作 Key 的类型之间就没有区别。 请记住,hashcode() 方法可能会被调用很多次,所以如果它很慢,您可以在 object 内部缓存它。

我有 ConcurrentHashMap 实例 map 可以通过多线程访问。见下面的代码片段。 这些怎么样?

Iterator<String> it = new TreeSet<String>(map.keySet()).iterator();
            while(it.hasNext())
            {
                id = it.next();
                synchronized(map)
                {
                    msg = map.get(id);
                    if(msg != null)
                        map.remove(id);
                }
                if(msg != null)
                listener.procMessage(msg);
            }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM