为大学第二学期的计算机科学创建两个结构来计算文本中的单词。 一种实现使用带有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,我不明白为什么地图确实需要这么多时间。 有人解释,也许是更好的解决方案吗?
答案 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您的基准可能存在缺陷。一个好的基准可能仍然会显示阵列表现更好,但不是那么明显。