问题 在局部性方面的数组与链接列表


假设我们有一个未排序的数组和链表。 搜索两个数据结构的元素时最糟糕的情况是O(n),但我的问题是:

由于在缓存中使用空间局部性,阵列是否仍然会更快,或者缓存是否会使用分支局部性,允许链表与任何阵列一样快?

我对数组的理解是,如果访问了一个元素,那么该存储器块和许多周围的块将被带入高速缓存,从而允许更快的存储器访问。

我对链表的理解是,由于遍历列表的路径是可预测的,因此缓存将利用它并仍然存储适当的内存块,即使列表中的节点在堆内可能相距很远。


9478
2017-09-28 07:09


起源

你谈到的这个“分支地点”是什么?缓存如何绕过主内存的延迟?请描述您认为缓存对链表节点的影响。
@delnan您可以在这里阅读有关分支机构的信息: en.wikipedia.org/wiki/Locality_of_reference  我不知道你的第二个问题的答案。我解释了我认为缓存可能会在我的问题结束时对节点做什么。 - Kacy
分支局部性的描述似乎是关于固定的一小组备选方案,例如分支指令的目标(因此名称)。相反,链表的下一个节点可能是 随地。至于我的第二个问题:问题缓存修复主要不是有限的带宽,而是有限的延迟。一次将大的连续块加载到缓存中(就像空间局部性/阵列一样)是一种改进,因为缓存只需要支付一次延迟成本。所以我的问题是,如何在不支付延迟成本n次的情况下缓存加载链表的节点?
这符合我的理解至少;-)
这个 停止使用链表 博客 & 你应该使用链表吗? 页面可能是相关的 - Basile Starynkevitch


答案:


您对阵列案例的理解大多是正确的。如果按顺序访问数组,许多处理器不仅会获取包含该元素的块,还会预取后续块以最大限度地减少等待缓存未命中所花费的周期。如果您使用的是Intel x86处理器,则可以在Intel x86优化中找到有关此内容的详细信息 手册。此外,如果数组元素足够小,则加载包含元素的块意味着下一个元素可能位于同一个块中。

不幸的是,对于链表,从处理器的角度来看,负载模式是不可预测的。在地址X处加载元素时,不知道下一个地址是(X + 8)的内容。

作为一个具体示例,顺序数组访问的加载地址序列很好且可预测。 例如,1000,1016,1032,1064等。

对于链表,它看起来像: 1000,3048,5040,7888等很难预测下一个地址。


12
2017-09-28 07:42