std :: unordered_set如何避免迭代中每个元素的潜在页面错误?

时间:2017-10-15 16:40:21

标签: c++ c++11 unordered-set

或者是吗?

澄清:在std::vector中,如果在迭代期间访问的某个元素当前不在缓存到内存中的页面上,则会出现页面错误并且该页面已加载,但随后会加载下一个k-1元素保证缓存到内存中k是适合内存页面的元素数。

在我看来,在像std::unordered_set这样的哈希表数据结构中,在迭代期间,对于任何被访问的元素都没有任何保证,后续元素将在内存中靠近它的任何地方,这意味着在生成中具有大量元素的条件,您可能会在迭代期间访问的每个元素都有潜在的页面错误。我错了吗?如果是这样,std::unordered_set使用什么方法来阻止这种情况?

好奇。我正在概述我计划立即实施的算法,并试图围绕如何使用有限的内存和退化条件下的大量元素进行预处理以及我对std::unordered_set如何在幕后工作的不完整知识这是一个限制因素。

3 个答案:

答案 0 :(得分:3)

没有。 std::unordered_set使用哈希表实现,单独链接。也就是说,每个存储桶都有一个链表,它会增长以存储存储桶的项目。这意味着,当您逐桶遍历时,您必须每次都取消引用指向动态内存的指针,并冒着缓存未命中的风险。

如果你想要类似的东西使用连续内存并因此在迭代时避免页面错误,你可以使用带有开放寻址的哈希表。例如,您可以使用线性探测,或使用像布谷鸟哈希这样的东西。但是您必须自己实现这些或使用其他人的非标准容器库。这些类型的映射和集合不能以尊重标准映射和集合的迭代器失效要求的方式完成。

答案 1 :(得分:1)

无序和有序关联容器都必然会受到引用内存的不连续性的影响。

我写了#34;必然",因为C ++标准坚持只要元素没有从容器中删除,指针和对关联容器中元素的引用仍然有效。这使得某些技术不可能改进参考的局部性,这需要移动元素来改善存储器布局。

内存分散不仅仅(或者甚至主要)导致过多的分页。最明显的后果通常是降低内存缓存利用率,这可以显着增加运行时间。 (显然,过度交换也会产生巨大的影响,但是如果你记住我们的限制,那么无论哈希表引用位置如何,你都会遇到问题。)

确实存在缓存感知算法,但有几个原因导致它们不经常使用:

  1. 优化仅适用于某些非常具体的用例。

  2. 在不了解被散列数据的情况下,很难编写一个缓存感知算法。通用库函数可以使用任何数据类型,很少为特定数据类型提供优化的特化。

  3. 标准关联容器的参考稳定性在大量用例中非常有用。

答案 2 :(得分:0)

无序列表可以被认为是一个向量(由键的哈希键控),带有类似哈希元素的链表。

通过无序列表的迭代迭代向量(共享相同的页面错误模式),然后是链接列表。如果没有共享插槽的项目,它将具有与向量相同的读取模式。

由于它是无序的,因此该迭代是数据的随机视图。