【问题标题】:How does an std::unordered_set avoid potential page faults on every element in iteration?std::unordered_set 如何避免迭代中每个元素的潜在页面错误?
【发布时间】:2017-10-15 16:40:21
【问题描述】:

是吗?

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

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

只是好奇。我正在概述一个我计划现在实施的算法,并试图围绕它如何在有限的内存和退化条件下的许多元素以及我对 std::unordered_set 如何在引擎盖下工作的不完全了解是一个限制因素在这里。

【问题讨论】:

  • "std::unordered_set 使用什么方法来防止这种情况发生?" 一般不会尝试。在实践中,您必须非常不走运,或者您的机器内存非常不足,才能为每个元素获取页面错误。
  • 实际上刚刚加载的带有vector 元素的页面可能会被卸载回页面文件,并且访问同一页面上的下一项将导致另一个页面错误。基本上大多数 C++ 应用程序只是通过将实际内存管理委托给系统来处理这个问题,假设使用语言方式分配的内存是可访问的。
  • 为我定义不幸。假设我想破坏一个 unordered_set 并使其对于一些非常大的 n 个元素尽可能慢。有没有办法做到这一点(可能是像不断地随机插入和删除元素,插入的机会只有稍微高一点,直到我得到 n 个元素,或者通过删除大序列的连续元素等)还是只是一个概率完全独立于我对场景所做的事情?
  • 提供一个自定义的operator new,它实现了一个将分配分散到尽可能多的物理页面的堆。然后对系统施加沉重的内存压力以迫使其抖动。
  • "如果在迭代期间访问的元素当前不在缓存到内存中的页面上,则会出现页面错误" - 在某些架构上,但在其他架构上没有,它们没有页面或页面的概念故障。所以,C++ 没有解决这个问题。

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


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

    我写的是“必然”,因为 C++ 标准坚持认为,只要元素没有从容器中删除,对关联容器中元素的指针和引用就保持有效。这使得某些技术无法实现,例如提高参考位置,这需要移动元素来改善内存布局。

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

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

    1. 优化只在一些非常具体的用例中有用。

    2. 如果不了解被散列的数据的很多信息,就很难编写一个缓存感知算法。通用库函数预计可用于任何数据类型,很少为特定数据类型提供优化的特化。

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

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

        猜你喜欢
        • 2021-07-09
        • 2018-09-14
        • 2020-11-23
        • 1970-01-01
        • 2017-11-27
        • 2012-09-21
        • 1970-01-01
        • 2010-11-14
        相关资源
        最近更新 更多