【问题标题】:Map vs Unordered_map-- MultithreadingMap vs Unordered_map——多线程
【发布时间】:2013-08-05 11:06:45
【问题描述】:

我有以下要求:

我需要一个包含键值对的数据结构(如果有帮助,键是整数)。

我需要以下操作:-

  1. 迭代(最常用)
  2. 插入(第二常用)
  3. 按键搜索和删除(最少)

我计划在结构上使用多个锁来进行并发访问。 理想的数据结构是什么?

地图还是无序地图?

我认为无序映射是有意义的,因为我可以在 O(1) 中插入,在 O(1) 中删除。但我不确定迭代。与地图相比,性能有多差?

另外,我计划在块上使用多个锁而不是整个结构。有什么好的实现例子吗?

谢谢

【问题讨论】:

    标签: c++ multithreading c++11 map unordered-map


    【解决方案1】:

    两个容器的迭代器递增速度为O(1),尽管您可能会从std::unordered_map 获得更好的缓存局部性。

    除了std::map 的较慢的O(log N) 查找/插入/擦除功能之外,另一个区别是std::map 提供双向 迭代器,而更快(摊销的O(1) 元素访问) std::unordered_map 仅提供 forward 迭代器。

    Anthony Williams 的优秀书籍C++ Concurrency in Action: Practical Multithreading 提供了一个多线程unordered_map 的代码示例,每个条目都有一个锁。如果您正在做认真的多线程编码,强烈推荐这本书。

    【讨论】:

      【解决方案2】:

      unordered_map 中迭代不是问题。它的效率比向量低一点,但在很大程度上不是这样。

      与往常一样,您需要针对您的用例进行基准测试,并与其他容器类型进行比较(如果它是您代码的关键部分)。

      不确定“块而不是整个结构上的多个锁”是什么意思 - 任何容器更新都需要为整个容器锁定......

      【讨论】:

      • 我的意思是在内部将哈希结构划分为多个块,并且只在容器的那些块上应用锁,而不是在整个容器上。假设一个结构有 10000 个桶,我可以在内部将其分解为 100 个块,每块 100 个桶并只锁定这些块
      • 所以,您不打算使用std::unordered_map - 如果不是这样,我们应该如何告诉您效率如何?
      • 如果我太天真了,我很抱歉,但我不清楚为什么这是不可能的。是否不可能在 unordered_map 周围有一个包装类,我可以确保特定元素[映射到特定块]只能通过特定锁访问?
      • 我认为如果不侵入类本身就无法做到这一点。而包装器并不能真正做到这一点。您需要知道 47112121 和 139198 是否最终在同一个存储桶中,而知道这一点的唯一方法是了解实际的实现。
      • 哦,我太天真了:P。我以为我可以定义自己的哈希函数并获取该信息。我会研究更多,想出我自己的哈希实现。无论如何感谢您的信息
      【解决方案3】:

      为什么不简单地使用现有的concurrent_unordered_map,您可以在TBBConcrt 中找到它。

      【讨论】:

        【解决方案4】:

        有没有想过尝试std::deque 原因如下:

        1. 迭代速度很快 - 数据应该或多或少地紧缩在一起(与列表不同)
        2. 插入(在任一端)应该很快 - 双端队列中的数据永远不会调整大小
        3. 迭代和删除速度慢(但不常见的用例)。

        如果最后两种情况很常见,则可以使用std::list。还可以考虑测试 std::vector`,因为它的缓存效率更高。

        unordered_map 中的迭代可能会因为迭代哈希表中大量未使用的元素而变慢。插入将停止,直到碰撞级别变得无法容忍,此时整个数据结构将需要重新布局。

        maps 的迭代速度相对较快,只是数据元素可能相距甚远。由于这需要重新平衡红黑树,插入可能会很慢。

        unordered_maps 的主要用例是用于快速查找 (O1)。法线贴图具有快速查找(O log n)但迭代性能要好得多。

        【讨论】:

        • “由于迭代哈希表中大量未使用的元素,unordered_map 中的迭代可能会很慢。” 质量实现可以轻松避免这种情况,例如GCC 无序容器中的存储桶可以将迭代器存储到元素的单链表中:迭代时,不会检查存储桶本身。
        【解决方案5】:

        如果您有严格的实时要求,我建议您使用 map 而不是 unordered_map。 std::map 保证了 100% 的性能,但 std::unordered_map 可能会在某些关键的极端情况下进行重新哈希并完全破坏实时性能。一般来说,如果我需要绝对保证最坏情况下的性能,我更喜欢红黑树 (std::map) 而不是哈希表 (std::unordered_map)。

        【讨论】:

          猜你喜欢
          • 2011-05-29
          • 2018-08-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-03-29
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多