【问题标题】:Java / HashMap / PerformanceJava / HashMap / 性能
【发布时间】:2016-02-14 15:32:19
【问题描述】:

这是我的 HashMap 实现的 put() 方法。 100 000 个元素的运行时间约为 1500 毫秒,而Collections 的 HashMap 运行时间为 8 毫秒。

是什么让性能有如此大的差异?

(我的哈希函数只是基于 hashCode(),负载因子在 0.6 左右,所以它应该表现良好)

public boolean put(K key, V value)
{
    if (size > cap*LOAD_FACTOR) expand();

    int i;  
    for(i=hash(key);container[i] != null;i=(i+1) % cap)
    {
        if(container[i].key.equals(key))
        {
            container[i] = new Entry<K,V>(key,value);
            return true;
        }               
    }

    container[i] = new Entry<K,V>(key,value);
    size++;

    return true;

【问题讨论】:

  • 您是如何衡量这些数字的?如果你没有使用合适的基准测试工具,你可以把它们从阳台上扔掉。
  • 控制台和System.nanotime() 与热身阶段:)
  • 您通常无法与 JVM 实现竞争。它们针对不同的类型、内存分配等进行了高度优化。一些容器直接与底层原生代码一起工作,这是纯 Java 实现无法实现的
  • Tunaki 是对的,有限数量的不可靠测试并不意味着什么
  • 如果你事先知道条目的数量,你可以设置初始容量。不能解决根本原因,但可能已经足够好了,因为您从不展开()

标签: java performance hashmap


【解决方案1】:

使用% 是一项非常昂贵的操作,实际上 HashMap 并没有使用它,即它的大小始终是 2 的幂,以允许掩码完成这项工作。在您的情况下,单个操作可能会多次调用%,尤其是在您的负载因子不够高的情况下。 尝试删除%

注意:如果您像以前一样使用开放寻址,则需要降低负载因子,例如小于 0.5。 HashMap 具有更高的负载因子,因为它以不同的方式处理冲突。

还要注意;

  • 创建一个新的中等寿命对象非常昂贵,我会在更新值时避免这种情况。
  • 你可以缓存hashCode来加速expand(),这意味着你可以在执行equals()之前比较hashCode

【讨论】:

  • 您对 % 运算符是完全正确的。我将其替换为i = (i &lt; (cap-1)) ? i+1 : 0,性能提高到 250 毫秒。然后我稍微降低了负载因子,现在它运行 35 :) 谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-17
  • 2018-04-09
  • 2018-03-02
  • 2023-04-07
  • 2011-10-05
  • 2012-08-13
  • 1970-01-01
相关资源
最近更新 更多