Hashmap 与数组性能

Posted

技术标签:

【中文标题】Hashmap 与数组性能【英文标题】:Hashmap vs Array performance 【发布时间】:2011-09-21 16:01:28 【问题描述】:

当 Array 的索引已知时,使用 Arrays 或 HashMaps 是否更好(在性能方面)?请记住,示例中的“对象数组/映射”只是一个示例,在我的实际项目中它是由另一个类生成的,所以我不能使用单个变量。

数组示例:

SomeObject[] objects = new SomeObject[2];
objects[0] = new SomeObject("Obj1");
objects[1] = new SomeObject("Obj2");

void doSomethingToObject(String Identifier)
    SomeObject object;
    if(Identifier.equals("Obj1"))
        object=objects[0];
    else if()
        object=objects[1];
    
    //do stuff

HashMap 示例:

HashMap objects = HashMap();
objects.put("Obj1",new SomeObject());
objects.put("Obj2",new SomeObject());

void doSomethingToObject(String Identifier)
    SomeObject object = (SomeObject) objects.get(Identifier);
    //do stuff

HashMap 看起来好多了,但我确实需要在这方面表现出色,以便优先考虑。

编辑:那么阵列就是这样,仍然欢迎提出建议

编辑:我忘了说,Array/HashMap 的大小总是一样的 (6)

编辑: HashMap 似乎更快 数组:128ms 哈希:103ms

当使用更少的周期时,HashMaps 的速度甚至是原来的两倍

测试代码:

import java.util.HashMap;
import java.util.Random;

public class Optimizationsest 
private static Random r = new Random();

private static HashMap<String,SomeObject> hm = new HashMap<String,SomeObject>();
private static SomeObject[] o = new SomeObject[6];

private static String[] Indentifiers = "Obj1","Obj2","Obj3","Obj4","Obj5","Obj6";

private static int t = 1000000;

public static void main(String[] args)
    CreateHash();
    CreateArray();
    long loopTime = ProcessArray();
    long hashTime = ProcessHash();
    System.out.println("Array: " + loopTime + "ms");
    System.out.println("Hash: " + hashTime + "ms");


public static void CreateHash()
    for(int i=0; i <= 5; i++)
        hm.put("Obj"+(i+1), new SomeObject());
    


public static void CreateArray()
    for(int i=0; i <= 5; i++)
        o[i]=new SomeObject();
    


public static long ProcessArray()
    StopWatch sw = new StopWatch();
    sw.start();
    for(int i = 1;i<=t;i++)
        checkArray(Indentifiers[r.nextInt(6)]);
    
    sw.stop();
    return sw.getElapsedTime();




private static void checkArray(String Identifier) 
    SomeObject object;
    if(Identifier.equals("Obj1"))
        object=o[0];
    else if(Identifier.equals("Obj2"))
        object=o[1];
    else if(Identifier.equals("Obj3"))
        object=o[2];
    else if(Identifier.equals("Obj4"))
        object=o[3];
    else if(Identifier.equals("Obj5"))
        object=o[4];
    else if(Identifier.equals("Obj6"))
        object=o[5];
    else
        object = new SomeObject();
    
    object.kill();


public static long ProcessHash()
    StopWatch sw = new StopWatch();
    sw.start();
    for(int i = 1;i<=t;i++)
        checkHash(Indentifiers[r.nextInt(6)]);
    
    sw.stop();
    return sw.getElapsedTime();


private static void checkHash(String Identifier) 
    SomeObject object = (SomeObject) hm.get(Identifier);
    object.kill();

【问题讨论】:

等待;如果您“真的需要性能”,那么您已经知道这个问题的答案,因为您会分析您的应用程序以确定这个 Hashmap 与 Array 问题实际上是相关的。如果您没有这样做,您需要这样做以确定这确实会影响您的表现并且实际上并没有浪费时间。 好点子,但是作为一个新手程序员,如果你错过了什么或得到更好策略的建议,得到一些思考总是很好的 doSomethingToObject 多久调用一次?是的,新手程序员应该认真对待的建议是 Dour High Arch 的建议。 如果你“真的需要性能”你不应该用java写... Dasdasd,您必须使用真实数据对运行的实际应用程序进行基准测试。用两个样本点编造虚假的“基准”只会误导你。您必须对整个应用程序进行基准测试并优化瓶颈,而不是选择看起来更改起来很有趣的代码行。如果这个问题不是瓶颈,那么无论你做多快,优化它都不会提高性能。 【参考方案1】:

HashMap 在下面使用一个数组,所以它永远不会比正确使用数组更快。

Random.nextInt() 比您正在测试的要慢很多倍,即使使用数组来测试数组也会使您的结果产生偏差。

您的数组基准测试如此缓慢的原因是由于等于比较,而不是数组访问本身。

HashTable 通常比HashMap 慢得多,因为它做的事情大致相同,但也是同步的。

微基准测试的一个常见问题是 JIT,它非常擅长删除不执行任何操作的代码。如果你不小心,你只会测试你是否对 JIT 感到困惑,以至于它无法锻炼你的代码什么都做不了。

这是您可以编写优于 C++ 系统的微基准的原因之一。这是因为 Java 是一种更简单的语言,更容易推理并因此检测出无用的代码。这可能会导致测试表明 Java 比 C++ 更快地执行“无用”;)

【讨论】:

好点,Java 基本上足够聪明,不需要时什么也不做 @PeterLawrey 有没有办法判断哪些代码被“JIT”淘汰了?我通常在这个基准测试中使用 caliper 框架,但他们提出了同样的建议——“小心”.. @Eugene 我说的代码现在快得不可思议。例如每次迭代花费的时间远少于一个时钟周期。这在重复测试中表现得最好。【参考方案2】:

知道索引的数组更快(HashMap 在后台使用链表数组,这在数组访问之上增加了一些开销,更不用说需要完成的散列操作了)

FYI HashMap&lt;String,SomeObject&gt; objects = HashMap&lt;String,SomeObject&gt;(); 做到了,所以你不必投射

【讨论】:

“数组更快”充其量是过于简单化,最坏的情况是完全错误。数组和哈希表是苹果和橘子。在给定数组索引的情况下查找数组中的值和在给定其键的情况下查找哈希表中的项都是渐近等效的:O(1)(在哈希表的情况下,摊销 O(1))。但是遍历一个数组来找到一个给定的键要糟糕得多:平均为 O(n/2),渐近为 O(n)。诚然,数组实现可能在这种情况下胜出,但您的回答暗示这是一般规则。 @daniel 好吧,“当数组的索引已知时”指向数组是赢家,但我会在答案中明确编辑警告【参考方案3】:

这个例子很奇怪。关键问题是您的数据是否是动态的。如果是这样,您就不能那样编写程序(如在数组情况下)。换句话说,您的数组和哈希实现之间的比较是不公平的。散列实现适用于动态数据,但数组实现不适用。

如果您只有静态数据(6 个固定对象),则数组或散列仅用作数据持有者。你甚至可以定义静态对象。

【讨论】:

如前所述,数据是在另一个类中创建的,因此数组/哈希图确实可以作为数据持有者【参考方案4】:

从逻辑上讲,HashMap 绝对适合您的情况。从性能的角度来看也是胜利的,因为在数组的情况下,您将需要进行多次字符串比较(在您的算法中),而在 HashMap 中,如果负载因子不太高,您只需使用哈希码。如果添加许多元素,则数组和 HashMap 都需要调整大小,但在 HashMap 的情况下,您还需要重新分配元素。在这个用例中 HashMap 失败了。

【讨论】:

考虑到这一点,我想我会进行一些测试,看看哪种方法最好。感谢您的信息 获得结果后请添加。对于数据集大小 6,调整大小显然无关紧要。【参考方案5】:

数组通常比集合类更快。

PS。您在帖子中提到了 HashTable。 HashTable 的性能比 HashMap 还要差。我认为您提到的 HashTable 是一个错字

"HashTable 看起来很多 更好的“

【讨论】:

【参考方案6】:

对于显示的示例,我相信 HashTable 胜出。数组方法的问题在于它不能扩展。我想你想在表中有两个以上的条目,并且 doSomethingToObject 中的条件分支树会很快变得笨拙和缓慢。

【讨论】:

只是切碎的话 - 对于所示的示例,数组可能会获胜。但是对于另一个需要检查更多 Identifier 值的示例,您所说的成立。 数组的长度也是已知的(如果重要,则为 6)

以上是关于Hashmap 与数组性能的主要内容,如果未能解决你的问题,请参考以下文章

Java基础教程:HashTable与HashMap比较

Day782.HashMap的设计与优化 -Java 性能调优实战

深入理解Java编程性能调优——深入浅出HashMap的设计与优化

如何使HashMap性能最差

什么是hashMap,初始长度,高并发死锁,java8 hashMap做的性能提升

java - HashMap