http://tinyurl.com/pzpyvb9 上的无锁堆栈的性能数据是不是现实?

Posted

技术标签:

【中文标题】http://tinyurl.com/pzpyvb9 上的无锁堆栈的性能数据是不是现实?【英文标题】:Is performance data for a lockfree stack at http://tinyurl.com/pzpyvb9 realistic?http://tinyurl.com/pzpyvb9 上的无锁堆栈的性能数据是否现实? 【发布时间】:2013-10-03 16:26:10 【问题描述】:

在http://blog.memsql.com/common-pitfalls-in-writing-lock-free-algorithms/ 的末尾,David Stolp 显示了无锁堆栈的性能数据,表明无锁版本比受互斥体保护的顺序版本慢,即使争用增加。结果很有趣,但有两件事让我担心:

充其量,“总吞吐量”会随着线程数的增加而降低,然后趋于平稳。总吞吐量不应该随着线程数量的增加而增加吗? 在最终图表中,1 个线程的性能值范围约为 35M 到 55M。对于 1 个线程来说,这似乎是一个非常广泛的范围(不能有任何争用)。

我试图找到一种方法就这些问题与作者联系,但没有成功,所以我转向 SO 社区,看看结果是否现实。是吗?

【问题讨论】:

我可以看到互斥体版本最慢。 @GJ:据我所知,基于互斥锁的版本与“天真”无锁版本的速度基本相同(慢)(根据最终图表)。它可能会慢一点,但是,你是对的。但这并不影响我关于吞吐量的问题,因为线程数增加或单个线程的吞吐量值范围很广。 【参考方案1】:

充其量,“整体吞吐量”会下降,然后随着 线程数增加。总吞吐量不应该增加 线程数增加了?

这很正常!堆栈只有一个!瓶颈是线程之间的内存同步,而不是代码执行。因此,如果更多的线程填满堆栈,那么应该会发生更多的内存冲突(出现竞争条件),因此吞吐量会降低。

在最终图表中,1 个线程的性能值范围为 大约 35M 到 55M。对于 1 个线程来说,这似乎是一个非常广泛的范围 (不能有任何争用)。

这个测试代码是不现实的,因为它只是将节点弹出并推入堆栈。因此,相对较短代码的最小差异会显着影响吞吐量。

如果您检查代码,您会发现 SpinLock 版本非常简单并且可能比 LockFree 更快,因为它是使用 test_and_set atomic 函数制作的,通常比 atomic CAS(比较和交换)快用于LockFree版本。

编辑:

在 LockFree 版本使用 cmpxchg16b 这是 16 字节 CAS 在 SpinLock 仅使用 8 字节 test_and_set 函数(用 cmpxchg8b 实现)所以存在速度差异!

【讨论】:

如果测试代码在堆栈操作之间做了一些工作(例如,做一些工作来为堆栈准备一个对象,然后推送它;在弹出一个元素后,做一些工作),我们' d 期望吞吐量随着线程数量的增加而增加,对吗?另外,我是否正确,您下载了基准代码并查看了它? @KnowItAllWannabe:检查代码是如何为 LockFree 和 SpinLock 制作线程安全程序堆栈的。在 LockFree 版本使用 cmpxchg16b 这是 16 字节 CAS 在 SpinLock 仅使用 8 字节 CAS cmpxchg8b 所以存在速度差异! 我将此标记为已接受的答案,因为它首先出现。下面大卫·哈曼的回答基本相同,但更容易阅读。【参考方案2】:

充其量,“整体吞吐量”会随着线程数量的增加而降低,然后趋于平稳。总吞吐量不应该随着线程数量的增加而增加吗?

不一定,在这种情况下也绝对不是。如果执行线程可以同时运行,多线程是有益的。如果线程永远不能同时运行,或者几乎所有的执行都涉及对单个资源的争用,那么最好将应用程序设为单线程。

此测试旨在使线程不能同时运行。几乎所有的代码都在争夺一个资源,一个堆栈。在这里故意使用这种名义上糟糕的设计,以便测试各种并发执行方案的开销,并测试各种方案处理争用的能力。

在最终图表中,1 个线程的性能值范围约为 35M 到 55M。对于 1 个线程来说,这似乎是一个非常广泛的范围(不能有任何争用)。

即使没有争用,锁定和解锁互斥体也会产生大量开销。比较和交换的开销要少得多,测试和设置的开销更少。当只有一个执行线程时,要测试的就是纯开销。

【讨论】:

以上是关于http://tinyurl.com/pzpyvb9 上的无锁堆栈的性能数据是不是现实?的主要内容,如果未能解决你的问题,请参考以下文章