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

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)。

【讨论】:

以上是关于Map vs Unordered_map——多线程的主要内容,如果未能解决你的问题,请参考以下文章

std::unordered_map 上的线程安全包装器

unordered_map 中的 C++ 线程(无复制构造函数)

不断迭代的线程安全的 Unordered_map

如何以线程安全的方式使用`std::unordered_map`?

多个线程同时在 unordered_map 中添加值使其崩溃

预分配 unordered_map 的线程安全