无锁链表的性能比锁定链表差
Posted
技术标签:
【中文标题】无锁链表的性能比锁定链表差【英文标题】:Lock free linked list is performing worse than the locked counterpart 【发布时间】:2016-07-12 19:45:16 【问题描述】:我正在尝试比较锁定和无锁定链表数据结构的性能。我已经为无锁链表实现了this 算法。这两个程序都是用 C 语言实现的。
我正在测试 4 个线程。每个线程有 1000 次插入操作。
我正在使用英特尔 PCM 工具来测量性能。
这是我的发现: 无锁:
Median of L3 Misses=1012699
Median of L2 Misses=1479741
Median of L3 Hits=484128
Median of L2 Hits=1797537
Median of Time=1.80696
Median of Cycles=5296042019
Median of IPC=1.536135
Median of Bytes Read=444423232
Median of Bytes Written=25414144
锁定:
Median of L3 Misses=711796.5
Median of L2 Misses=1517899
Median of L3 Hits=819408.5
Median of L2 Hits=2282527
Median of Time=0.244517
Median of Cycles=894265192
Median of IPC=0.8495695
Median of Bytes Read=174872576
Median of Bytes Written=24722912
锁定版本在除 IPC 之外的所有计数上都表现更好。这是应该发生的事情吗?还是 lock Free 数据结构应该表现更好?
如果是,那么使用无锁数据结构有什么好处? 任何帮助将不胜感激。
【问题讨论】:
转到此页面:***.com/questions/33083270 在该页面上有一个 YouTube 视频链接,指向 CppCon 上关于无锁实现和权衡的演讲。视频分为两部分,第 2 部分的链接。所以,找到第 1 部分。视频总共大约 2 小时,但演讲者很有趣,而且非常了解他的东西 这个answer 可能会解释性能问题(争用)。无锁数据结构可能有助于避免昂贵的上下文切换。 您没有看到真正的问题。缓存命中率绝对可怕,这是现代处理器上传统链表的标准问题。这些旧论文忽略了一个非常重要的细节。不要使用它们。 【参考方案1】:锁定版本在除 IPC 之外的所有计数上都表现更好。这是应该发生的事情吗?还是 lock Free 数据结构应该表现更好?
一般来说,性能更好的是工作负载细节和实现细节的函数。你引用的论文说
无锁数据结构也有潜力获得更好的性能
(强调),但它并不能保证在每种情况下都有更好的性能。尽管多个线程可能能够同时修改无锁数据结构,但即使没有冲突,每次修改都涉及更多操作。当存在冲突时,性能会下降。
我还观察到,您的无锁代码的缓存未命中率高于锁定代码。尽管我不能自信地解释这一点,但我至少可以想到两个可能的原因,说明这将是无锁实现的预期结果。自然,低效的缓存使用会显着降低性能。
如果是,那么使用无锁数据结构有什么好处?
论文说主要的好处是:
如果实现是无锁的,单个进程的延迟或故障不会阻塞系统中其他进程的进度。
【讨论】:
感谢您的回答。有关如何减少缓存未命中的任何帮助? @Sumant,缓存命中率主要是数据访问模式的函数,它本身是工作负载和实现细节的函数,就像整体性能一样。在可能的情况下,您更喜欢线性扫描内存并避免跳来跳去。您可能会促进这一点的一种方法是在中等规模的组中分配列表节点,而不是一次一个。布置结构成员以最小化填充也可能会有所帮助。 然而,总体而言,您不太可能使用这些技巧来弥补两种方法之间观察到的性能差异。如果性能是您的首要任务,请使用模拟预期工作负载的工作负载测试每种方法,然后选择性能更好的方法。 我正在做我的研究生项目的一部分。我的目标是从无锁链表中挤出大部分性能。我在每个插入操作上分配一个节点的空间。关于如何优化代码的任何提示?让我知道是否有代码链接。 @Sumant,如果这是一个研究生项目,那么与您的研究生导师讨论优化问题是合适的。此外,如果您的代码有效(看起来确实如此),那么您可以考虑将其发布到CodeReview 以供审核。但是,如果您选择这样做,请务必仔细阅读并遵守他们的规则,这与我们在 SO 的规则略有不同。以上是关于无锁链表的性能比锁定链表差的主要内容,如果未能解决你的问题,请参考以下文章