【问题标题】:What is the fastest possible solution for concurent read/write into hash-maps?并发读/写哈希映射的最快解决方案是什么?
【发布时间】:2017-09-29 13:18:41
【问题描述】:

我正在编写一个网络服务,它接收原始数据包然后将它们转换并将它们放入队列中,还有几个工作线程从队列中获取转换后的数据包并根据一些规则更新哈希映射。为了防止来自不同工作线程的哈希映射的并发更新,我必须使用互斥锁。不幸的是,使用互斥锁会对性能造成很大影响。我需要为此找到解决方法。

编辑: 转换后的数据包包含一个sessio_id,这个session_id被用作hash-map key。在任何插入或更新之前,首先搜索 session_id,如果没有找到 session_id,则 添加一个新条目这正是我使用互斥锁的地方,否则如果 session_id 已经存在,我只是 更新 现有值,并且没有用于单纯值更新的互斥锁。知道我使用 boost::unordered_map 作为底层哈希映射可能会有所帮助。

下面是我使用的逻辑的伪代码:

   if hash.find(session_id) then
      hash.update(value)
   else
      mutex.lock()
      hash.insert(value)
      mutex.unlock()
   end

你有什么建议?

顺便说一下,这是我的工作环境和工具:

编译器:C++(gcc)

线程库:pthread

操作系统:Ubuntu 14.04

【问题讨论】:

  • 我认为您需要添加从 hashmap 中读取的频率、更新 hashmap 的频率以及您拥有的 hashmap 的读者数量。
  • @SergeiKurenkov 我添加了一些细节:)
  • 我认为您在这里遇到了错误:otherwise if the session_id already exists I just update the existing value and there is no mutex lock used for mere value update。添加一个新的key会导致hashmap在内部重新分配内存,同时在另一个线程中访问一个key肯定会导致错误。
  • 当其他线程正在插入东西时,您无法在互斥锁之外搜索地图。
  • 顺便说一句,我没有看到您更新的答案中读取/秒、写入/秒和读者数量的确切数字。

标签: c++ multithreading performance hashmap network-programming


【解决方案1】:

最快的解决方案是以每个线程使用自己的数据集的方式拆分数据,因此您根本不需要任何锁定。也许您可以通过根据一些关键数据在线程之间分发消息来实现。

第二个最佳解决方案是使用 C++ 11 原子或 C 库中的函数实现读写自旋锁,请参阅https://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html
读写自旋锁通常允许多个并行读取访问,但只允许一次写入访问(当然也阻止所有读取访问)。

Linux 中也有读写互斥锁,但我发现它比手工实现的速度稍慢。

【讨论】:

  • +1 我喜欢将会话 ID 与线程关联以避免完全锁定的想法,但是您需要一种机制来根据 ID 将读取和写入传递给特定线程,也无需 ID 进行搜索更难。
【解决方案2】:

您是否研究过无锁数据结构?您可以参考 Andrei Alexandrescu 和 Maged Michael 的一篇有趣的论文,Lock-Free Data Structures with Hazard Pointers。例如,可以在libcds Github 存储库中找到一些使用类似想法的实现。

虽然他们在某种程度上使用了锁定,但 Facebook 的 folly AtomiHashMap 和 Intel 的 TBB 也提供了高性能的并发哈希映射。

当然,这些方法需要一些额外的阅读和集成工作,但如果您确定当前的锁定策略是瓶颈,那么付出代价可能是值得的。

【讨论】:

    猜你喜欢
    • 2012-12-16
    • 1970-01-01
    • 1970-01-01
    • 2010-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多