【问题标题】:In what circumstances lock free data structures are faster than lock based ones?在什么情况下无锁数据结构比基于锁的数据结构更快?
【发布时间】:2017-03-10 05:38:44
【问题描述】:

我目前正在阅读 Anthony WilliamsC++ Concurrency in Action 书,其中有几种无锁数据结构实现。在安东尼正在写的书中关于无锁数据结构一章的前言:

这给我们带来了无锁和无等待代码的另一个缺点:虽然它可以增加数据结构上操作的并发性并减少单个线程等待的时间,但它很可能会降低整体性能。

事实上,我测试了本书中描述的所有无锁堆栈实现与前一章中基于锁的实现。而且似乎无锁代码的性能总是低于基于锁的堆栈。

什么情况下无锁数据结构更优,必须首选?

【问题讨论】:

  • 这多少数据?锁定版本花费了多长时间?
  • “必须是首选?”必须是一个非常强烈的词
  • 我喜欢无锁数据结构,因为它们有助于避免互斥锁死锁。当有很多争用时,它们会变慢,就像自旋锁一样。
  • 简而言之:只要没有线程实际上无法获取锁,基于锁就很好。当这种情况发生时,它几乎可以保证上下文切换,太糟糕了。如果有可能多个线程实际上会同时访问同一个临界区(大量争用),那么无锁的性能会更好。
  • 除了其他用例之外,它们对于以读取为主的数据非常有用。使用RCU 之类的东西,读者无需等待,甚至根本不需要进行原子操作。同步的负担可以完全由作者承担。

标签: c++ multithreading data-structures concurrency lock-free


【解决方案1】:

我认为这些答案中缺少的一件事是锁定期。如果您的锁定周期很短,即如果您在很短的时间内执行任务(例如递增变量)获得锁定之后,那么使用基于锁定的数据结构会带来不必要的上下文切换、cpu 调度等。在这种情况下,无锁是一个不错的选择,因为线程会在很短的时间内旋转。

【讨论】:

  • 一个好的互斥体在非竞争情况下不涉及任何上下文切换或系统调用。 (preshing.com/20111124/always-use-a-lightweight-mutex)。当然,如果你真的只想增加一个标量计数器,那么无锁原子肯定是显而易见的选择。在某些机器上,这意味着根本没有旋转。但在更常见的情况下,是的,在极少数情况下,CAS 重试循环可能需要重试几次。
【解决方案2】:

无锁结构的一个好处是它们不需要上下文切换。然而,在现代系统中,非竞争锁也是无上下文切换的。要从无锁算法中受益(在性能方面),必须满足几个条件:

  • 竞争必须很高
  • 应该有足够的 CPU 内核,以便旋转线程可以不间断地运行(理想情况下,应该固定到自己的内核)

【讨论】:

  • 我认为这两个条件相互抵消。如果我们有足够的 cpu 核心,我们的争用就会减少。
  • @AnkushG 不是真的,为什么?
【解决方案3】:

这取决于发生碰撞的概率。

如果很可能发生冲突,则互斥锁是最佳解决方案。 例如:2个线程不断将数据推送到容器的末尾。 使用无锁只有 1 个线程会成功。另一个需要重试。在这种情况下,阻塞和等待会更好。

但是如果你有一个大容器,并且 2 个线程将在不同的区域访问容器,那么很可能不会发生冲突。 例如:一个线程修改容器的第一个元素,另一个线程修改最后一个元素。 在这种情况下,重试的概率很小,因此这里的无锁会更好。

无锁的其他问题是自旋锁(大量内存使用)、原子变量的整体性能以及对变量的一些限制。

例如,如果您有约束 x == y 需要为真,则不能对 x 和 y 使用原子变量,因为您不能同时更改这两个变量,而 lock() 将满足约束

【讨论】:

    【解决方案4】:

    几年前我做过性能研究。当线程数较少时,无锁数据结构和基于锁的数据结构具有可比性。但是随着线程数量的增加,基于锁的数据结构在某些时候表现出急剧的性能下降,而无锁数据结构可以扩展到数千个线程。

    【讨论】:

    • @Donghui Zhang 你是对的,这在很大程度上取决于线程数和每个节点存储的数据大小。我用 1000 个读写器线程进行了测试,这种方式看起来有利于无锁设计。
    【解决方案5】:

    互斥锁设计很少会胜过无锁设计。 那么接下来的问题是为什么有人会使用互斥锁而不是无锁设计?

    问题在于无锁设计很难做到,并且需要大量的设计才能可靠;虽然互斥锁相当微不足道(相比之下),但调试可能更难。出于这个原因,人们通常更喜欢先使用互斥锁,然后在证明争用成为瓶颈时再迁移到无锁。

    【讨论】:

    • "互斥锁设计很少会胜过无锁设计。"我不认为这是完全正确的。看起来纯粹是基于“理论”而不是经验。首先,“无锁”并不是真正的无锁,锁是在硬件级别完成的。第二个“无锁”并不意味着“无延迟”
    • 如果使数据结构无锁意味着通常简单的操作现在需要一系列原子操作,那么轻度竞争的数据结构实际上可能会从使用锁中受益。
    • 我看到了很多 - 与基于实现的轻量级细粒度用户级锁相比,具有无锁数据结构(例如优先级队列)的学术论文只是浪费时间。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多