Java hashmap vs hashset性能

use*_*803 5 java performance hashmap hashcode

我有一个760万行的文件。每行的形式为:A,B,C,D,其中B,C,D是用于计算A的重要性级别的值,A是每行唯一的字符串标识符。我的方法:

private void read(String filename) throws Throwable {
        BufferedReader br  = new BufferedReader(new FileReader(filename));

        Map<String, Double> mmap = new HashMap<>(10000000,0.8f);
        String line;
        long t0 = System.currentTimeMillis();
        while ((line = br.readLine()) != null) {
            split(line);
            mmap.put(splitted[0], 0.0);
        }
        long t1 = System.currentTimeMillis();
        br.close();
        System.out.println("Completed in " + (t1 - t0)/1000.0 + " seconds");
}

private void split(String line) {
    int idxComma, idxToken = 0, fromIndex = 0;
    while ((idxComma = line.indexOf(delimiter, fromIndex)) != -1) {
        splitted[idxToken++] = line.substring(fromIndex, idxComma);
        fromIndex = idxComma + 1;
    }
    splitted[idxToken] = line.substring(fromIndex);
}
Run Code Online (Sandbox Code Playgroud)

其中插入了虚拟值0.0以进行“概要分析”,并拆分了为该类定义的简单String数组。我最初使用String的split()方法,但发现上述方法更快。

当我运行上面的代码时,花12秒钟来解析文件,这比我认为的要多。例如,如果我用字符串向量替换HashMap并仅从每一行中获取第一个条目(即,我没有在其中添加关联的值,因为它应该摊销常量),所以整个文件的读取时间少于3秒

这向我表明(i)HashMap中存在很多冲突(我已尝试通过预先分配大小并相应地设置负载因子来最大程度地减少调整大小的次数),或(ii)hashCode()函数某种程度上很慢。我对此表示怀疑(ii),因为如果我使用HashSet,则可以在4秒内读取文件。

我的问题是:HashMap执行如此缓慢的原因可能是什么?hashCode()是否不足以容纳这种大小的地图,或者从根本上讲我忽略了某些东西?

iav*_*ish 3

HashMap 与 Vector:在 HashMap 中插入比在 Vector 中插入成本更高。虽然两者都是摊销常数时间操作,但 HashMap 在内部执行许多其他操作(如生成 hashCode、检查碰撞、解决碰撞等),而 Vector 只是在末尾插入元素(增加结构的大小,如果需要的话)。

HashMap 与 HashSet: HashSet 内部使用 HashMap。因此,如果您将它们用于相同目的,则不应有任何性能差异。理想情况下,这两者都有不同的目的,因此讨论哪个更好是没有意义的。

由于您需要 B、C、D 作为 A 作为键的值,因此您绝对应该坚持使用 HashMap。如果您确实只想比较性能,请将“null”而不是 0.0 作为所有键的值(因为这是 HashSet 在将键放入其支持的 HashMap 时使用的值)。

更新:HashSet 使用虚拟常量值(static final)插入到 HashMap 中,并且不为 null。对于那个很抱歉。您可以将 0.0 替换为任何常量,并且性能应该与 HashSet 类似。