3

我已经使用http://www.research.ibm.com/people/m/michael/ieeetpds-2004.pdf中解释的危险指针方法实现了一个无锁队列,使用 GCC CAS 指令用于实现,pthread 本地存储用于线程本地结构。我现在正在尝试评估我编写的代码的性能,特别是我试图在此实现与使用锁(pthread 互斥锁)来保护队列的实现之间进行比较。
我在这里问这个问题是因为我尝试将它与“锁定”队列进行比较,我发现这在无锁实现方面具有更好的性能。我尝试的唯一测试是在 4 核 x86_64 机器上创建 4 个线程,在队列上执行 10.000.000 次随机操作,它比无锁版本快得多。

我想知道您是否可以建议我遵循的方法,即我必须在队列上测试什么样的操作以及我可以使用什么样的工具来查看我的无锁代码在哪里浪费时间。

我还想了解无锁队列的性能是否可能仅仅因为 4 个线程不足以看到重大改进......

谢谢

4

3 回答 3

3

第一点:无锁编程不一定能提高速度。无锁编程(如果正确完成)保证了前进。当您使用锁时,一个线程可能会在持有互斥锁时崩溃(例如,进入无限循环)。当/如果发生这种情况,没有其他线程等待该互斥体可以取得更多进展。如果该互斥锁是正常操作的核心,那么您可能很容易不得不重新启动整个过程,然后才能完成更多工作。使用无锁编程,就不会出现这种情况。无论任何一个线程1发生什么,其他线程都可以向前推进。

也就是说,是的,您希望的一件事通常是更好的性能——但要看到它,您可能需要四个以上的线程。在数十到数百个线程的某个范围内,您的无锁代码将有更好的机会显示出比基于锁的队列更好的性能。然而,要真正做很多好事,你不仅需要更多线程,还需要更多内核——至少根据我目前所见,四个内核和编写良好的代码,可能还不够争用无锁编程的锁以显示很多(如果有的话)性能优势。

底线:更多线程(至少几十个)将提高无锁队列显示性能优势的机会,但只有四个内核,如果基于锁的队列仍然跟上,那就不足为奇了。如果你添加了足够多的线程和内核,那么无锁版本的胜出几乎是必然的。所需的线程和内核的确切数量很难预测,但您至少应该考虑几十个。


1至少就互斥锁之类的东西而言。像只吃掉所有系统资源的分叉炸弹之类的东西可能会剥夺其他线程足够的资源来完成任何事情——但是像配额这样的一些注意事项通常也可以防止这种情况发生。

于 2011-09-27T15:22:21.667 回答
1

问题实际上是您正在优化的工作负载。如果拥塞很少见,现代操作系统上的锁结构可能还不错。只要它们在快速路径上,它们主要使用 CAS 指令。由于这些已经非常优化,因此很难用您自己的代码击败它们。

我们自己的实现只能为拥塞的部分赢得实质性的胜利。如果平均队列长度比并行攻击它的线程数长得多,那么队列上的随机操作(你的问题不是太精确)可能不会这样做。因此,您必须确保队列很短,也许通过在队列太长或太短时引入关于所选择的随机操作的偏差。然后我还会用至少两倍于内核的线程来为系统充电。这将确保等待时间(内存)不会有利于锁定版本。

于 2011-09-27T15:22:01.313 回答
1

我认为最好的方法是通过分析代码来识别应用程序中带有锁的热点。引入无锁机制并再次测量。正如其他海报已经提到的那样,在较低规模(线程数、应用程序规模、内核数)下可能没有显着改善,但您可能会在扩大系统规模时看到吞吐量提高。这是因为已经消除了死锁情况并且线程总是在前进。

另一种看待无锁方案优势的方法是,在某种程度上,系统状态与应用程序性能分离,因为没有内核/调度程序参与,并且大部分代码都是用户态的,除了 CAS 这是一条硬件指令。

对于竞争激烈的锁,一旦获得锁,线程就会阻塞并被调度,这基本上意味着它们被放置在运行队列的末尾(对于特定的优先级)。不经意间,这会将应用程序与系统状态和响应时间联系起来app 现在取决于运行队列长度。

只是我的2美分。

于 2014-04-27T04:34:20.843 回答