gpt4 book ai didi

c++ - 什么时候 std::shared_timed_mutex 比 std::mutex 慢,什么时候(不)使用它?

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:14:25 33 4
gpt4 key购买 nike

我正在尝试使用 this 在 C++ 中实现多线程 LRU 缓存文章作为提示或灵感。它适用于 Go,但所需的概念或多或少也存在于 C++ 中。本文建议在散列表和链表周围使用带有共享互斥锁的细粒度锁定。

所以我打算用 std::unordered_map 写一个缓存, std::list并使用 std::shared_timed_mutex 锁定.我的用例包括几个线程 (4-8) 使用此缓存作为拼写错误的单词和相应可能的更正的存储。缓存的大小约为 10000-100000 个项目。

但是我在几个地方读到,使用共享互斥锁而不是普通互斥锁几乎没有意义,而且速度更慢,尽管我找不到一些带有数字的真实基准或至少在何时使用和何时不使用的模糊指南共享互斥锁。而其他来源建议在您有并发读取器或多或少超过并发写入器时使用共享互斥锁。

  • 什么时候使用 std::shared_timed_mutex 比较好比普通std::mutex ?读者/阅读人数应该多于作者/写作人数多少次?我当然知道这取决于很多因素,但是我应该如何决定使用哪个?
  • 也许它依赖于平台并且某些平台实现比其他平台更糟糕? (我们使用 Linux 和 Windows 作为目标,MSVC 2017 和 GCC 5)
  • 实现文章中描述的缓存锁定是否有意义?
  • 是否std::shared_mutex (来自 C++17)与定时相比在性能上有什么不同吗?

  • 附言我觉得会有“首先衡量/描述最适合您的情况”。我会,但我需要先实现一个,如果有一些启发式可供选择,而不是同时实现选项和测量,那就太好了。此外,即使我进行测量,我认为结果也将取决于我使用的数据。并且很难预测真实数据(例如,对于云中的服务器)。

    最佳答案

    1. When is it better to use an std::shared_timed_mutex than a plain std::mutex? How many times should readers/reads outnumber writers/writes? Of course I get that it depends on many factors, but how should I make a decision which one to use?


    由于它们额外的复杂性,读/写锁( std::shared_mutex std::shared_timed_mutex )优于普通锁( std::mutex std::timed_mutex )的情况很少见。它们确实存在,但就个人而言,我自己从未遇到过。

    如果您有频繁但短暂的读取操作,则读/写互斥不会提高性能。它更适合于读取操作频繁且昂贵的场景。当读操作只是在内存数据结构中查找时,很可能简单的锁会胜过读/写解决方案。

    如果读取操作的开销非常大,并且您可以并行处理许多操作,那么在某些时候增加读写比率应该会导致读取/写入器性能优于排他锁的情况。断点在哪里取决于实际工作量。我不知道一个好的经验法则。

    另请注意,在持有锁的同时执行昂贵的操作通常是一个坏兆头。可能有更好的方法来解决问题,然后使用读/写锁。

    在该领域比我拥有更多知识的人对这个话题发表了两条评论:
  • Howard Hinnant 的回答 C++14 shared_timed_mutex VS C++11 mutex
  • Anthony Williams 的引述可以在 this answer 的末尾找到。 (不幸的是,此原始帖子的链接似乎已失效)。他解释了为什么读/写锁很慢,而且通常不是理想的解决方案。

    1. Maybe it's platform-dependent and some platform implementations are worse than others? (we use Linux and Windows as targets, MSVC 2017 and GCC 5)


    我不知道操作系统之间的显着差异。我的期望是情况会相似。在 Linux 上,GCC 库依赖于 glibc 的读/写锁实现。如果你想深入了解,你可以在 pthread_rwlock_common.c 中找到实现.它还说明了读/写锁带来的额外复杂性。
    shared_mutex 有一个老问题Boost ( #11798 - Implementation of boost::shared_mutex on POSIX is suboptimal ) 中的实现。但是我不清楚这个实现是否可以改进,或者它是否只是一个不太适合读/写锁的例子。

    1. Does it make sense to implement cache locking as described in the article?


    坦率地说,我怀疑读/写锁会提高这种数据结构的性能。读取器操作应该非常快,因为它只是一个查找。更新 LRU 列表也发生在读取操作之外(在 Go 实现中)。

    一个实现细节。在这里使用链表并不是一个坏主意,因为它使更新操作非常快(您只需更新指针)。使用时 std::list 请记住,它通常涉及内存分配,当您持有 key 时应该避免这种分配。最好在获取锁之前分配内存,因为内存分配很昂贵。

    在他们的 HHVM 项目中,Facebook 有并发 LRU 缓存的 C++ 实现,看起来很有希望:
  • ConcurrentLRUCache
  • ConcurrentScalableCache
  • ConcurrentLRUCache LRU 列表也使用链表(但不是 std::list ),而 tbb::concurrent_hash_map 对于映射本身(来自英特尔的并发散列映射实现)。请注意,对于 LRU 列表更新的锁定,它们并没有像 Go 实现中那样采用读/写方法,而是使用了一个简单的 std::mutex排他锁。

    第二个实现( ConcurrentScalableCache )建立在 ConcurrentLRUCache 之上.他们使用分片来提高可扩展性。缺点是 LRU 属性只是近似值(取决于您使用的分片数量)。在某些可能会降低缓存命中率的工作负载中,这是一个很好的技巧,可以避免所有操作都必须共享相同的锁。

    1. Does std::shared_mutex (from C++17) make any difference in performance compared to a timed one?


    我没有关于开销的基准数字,但它看起来像是在比较苹果和橙子。如果您需要计时功能,您别无选择,只能使用 std::shared_timed_mutex .但是如果你不需要它,你可以简单地使用 std::shared_mutex ,它必须做更少的工作,因此永远不会变慢。

    对于需要超时的典型场景,我不希望计时开销太严重,因为无论如何在这种情况下锁往往会保持更长时间。但如前所述,我无法用实际测量来支持该声明。

    关于c++ - 什么时候 std::shared_timed_mutex 比 std::mutex 慢,什么时候(不)使用它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50972345/

    33 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com