为什么map.values()。stream()比Array.stream(array)慢得多

时间:2015-04-26 09:38:54

标签: java arrays hashmap

为大学第二学期的计算机科学创建两个结构来计算文本中的单词。 一种实现使用带有Word对象的Array,它将单词保存为字符串,其频率保存为int。 另一个用作HashMap,Word为键,频率为值。 现在他们是一个功能" totalWords"这应该返回所有频率的总和。

在HashMap变体中:

return _map.values().stream().reduce(0, (a, b) -> a + b);

在数组变体中:

return Arrays.stream(_words)
            .map((word) -> word != null ? word.count() : 0)
            .reduce(0, (a, b) -> a + b);

我的问题是:在测试文本非常短的JUnit测试中,Array变体确实需要大约0.001s,而地图变体需要0.040s,我不明白为什么地图确实需要这么多时间。 有人解释,也许是更好的解决方案吗?

2 个答案:

答案 0 :(得分:3)

其中一个原因是迭代HashMap可能比Array慢得多,原因是locality。现代处理器的计算瓶颈主要是内存访问,这就是使用cache的原因。 Array将数据存储在连续的内存块中,这意味着当您将该块内存交换到缓存中时,您更有可能使用缓存中的所有内容,或者获得cache hits,因此缓存喜欢连续的数据记忆。另一方面,HashMap的每个元素都存储在内存中的不同位置,因此当您遍历HashMap时,会获得大量缓存misses,最终会进行交换数据一直进出缓存,这会大大减慢你的程序速度。

虽然HashMap的实际实现是以优化的方式,使得内存中的数据聚集在一起,但即使在这种情况下,(@ Radiodef),因为HashMap使用某种{ {1}} linked list的每个元素都包含额外的指针,因此HashMap消耗的内存多于HashMap,更多的内存意味着Array更多cache misses },因此page faults通常比HashMap慢。

答案 1 :(得分:0)

HashMap是一个数据结构,它(基本上)有一个链表列表:

0: [ a ] -> [ b ] -> [ c ]
1: [   ]
2: [   ]
3: [ d ] -> [ e ]
4: [   ]
5: [ f ]
6: [   ]
7: [   ]

链接列表是键具有相同哈希码的位置(称为“冲突”)。

因此数据结构中有“漏洞”,并且它比数组更加碎片化,因为HashMap每个条目都有一个对象。迭代HashMap将从内存中生成比迭代数组更多的负载。

我也同意JB Nizet您的基准可能存在缺陷。一个好的基准可能仍然会显示阵列表现更好,但不是那么明显。