Map vs Unordered_map——多线程
Posted
技术标签:
【中文标题】Map vs Unordered_map——多线程【英文标题】:Map vs Unordered_map-- Multithreading 【发布时间】:2013-08-05 11:06:45 【问题描述】:我有以下要求:
我需要一个包含键值对的数据结构(如果有帮助,键是整数)。
我需要以下操作:-
-
迭代(最常用)
插入(第二常用)
按键搜索和删除(最少)
我计划在结构上使用多个锁来进行并发访问。 理想的数据结构是什么?
地图还是无序地图?
我认为无序映射是有意义的,因为我可以在 O(1) 中插入,在 O(1) 中删除。但我不确定迭代。与地图相比,性能有多差?
另外,我计划在块上使用多个锁而不是整个结构。有什么好的实现例子吗?
谢谢
【问题讨论】:
【参考方案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
,您可以在TBB 和Concrt 中找到它。
【讨论】:
【参考方案4】:有没有想过尝试std::deque
原因如下:
-
迭代速度很快 - 数据应该或多或少地紧缩在一起(与列表不同)
插入(在任一端)应该很快 - 双端队列中的数据永远不会调整大小
迭代和删除速度慢(但不常见的用例)。
如果最后两种情况很常见,则可以使用std::list
。还可以考虑测试 std::vector`,因为它的缓存效率更高。
unordered_map
中的迭代可能会因为迭代哈希表中大量未使用的元素而变慢。插入将停止,直到碰撞级别变得无法容忍,此时整个数据结构将需要重新布局。
map
s 的迭代速度相对较快,只是数据元素可能相距甚远。由于这需要重新平衡红黑树,插入可能会很慢。
unordered_maps 的主要用例是用于快速查找 (O1)。法线贴图具有快速查找(O log n)但迭代性能要好得多。
【讨论】:
“由于迭代哈希表中大量未使用的元素,unordered_map 中的迭代可能会很慢。” 质量实现可以轻松避免这种情况,例如GCC 无序容器中的存储桶可以将迭代器存储到元素的单链表中:迭代时,不会检查存储桶本身。【参考方案5】:如果您有严格的实时要求,我建议您使用 map 而不是 unordered_map。 std::map 保证了 100% 的性能,但 std::unordered_map 可能会在某些关键的极端情况下进行重新哈希并完全破坏实时性能。一般来说,如果我需要绝对保证最坏情况下的性能,我更喜欢红黑树 (std::map) 而不是哈希表 (std::unordered_map)。
【讨论】:
以上是关于Map vs Unordered_map——多线程的主要内容,如果未能解决你的问题,请参考以下文章
unordered_map 中的 C++ 线程(无复制构造函数)
如何以线程安全的方式使用`std::unordered_map`?