我一直在寻找提高处理从rabbitmq队列接收的消息的速度的方法。我发现的唯一方法是让不止一个线程做同样的事情 - 接收和处理。这给了我一些利润。在我创建4个线程后,速度翻了两番。因为我有8核处理器,所以我决定将线程数增加到8.但这并没有增加性能。 YourKit显示只使用了50%的CPU。有人可以说我的应用程序是轻量级的,所以它是如此,但我可以说它不能做更多的工作,不管我做了多少工作。为什么这不起作用?
答案 0 :(得分:4)
有许多不同的问题会限制某个应用程序在给定系统上的最大速度。例如,它可以受内存带宽,Amdahl's Law效果(非并行代码所需的时间,包括同步块),I / O带宽和缓存空间的限制。
如果你想进一步改进,你需要做一些测量和分析,找出时间的去处,然后再进行研究。
答案 1 :(得分:3)
简短(并不是特别有帮助)的答案是“开销和瓶颈”。
例如:
用Java创建线程相对昂贵。如果一个线程完成的工作量不大,那么创建线程的开销可能会超出好处。
线程之间的上下文切换相对昂贵,尤其是当您考虑到与内存相关的开销时,例如缓存未命中,TLB未命中。 (当本机线程被分配给核心时,实际上会遇到这些开销。如果操作系统能够以某种方式连续保持单个核心上的本机线程(即同一核心上没有其他线程),那么它可以使用自旋锁...避免上下文切换。但是你拥有的Java线程越多,操作系统就越不可能做到这一点。)
线程可能花费大部分时间等待I / O完成。 I / O系统的吞吐量或某些外部服务的速度/延迟可能成为瓶颈。
您可能会对数据结构产生争议;例如需要独占访问权限的线程可以安全地读取或更新(比如说)共享Map。如果线程经常需要等待其他人释放锁,那么你就会遇到瓶颈。
您的计算可能由“喂养”线程的成本占主导地位。例如,如果有一个主线程向工作线程发出“工作”,那么主线程的活动可能是瓶颈;即它可能无法提供足够的工作来保持工人忙碌。
由于您的标签暗示您正在使用消息队列,因此可能是瓶颈,特别是如果消息很大或者每个消息的“工作”相对较小。
(使用单独的单独消息队列服务可能会增加上下文切换,增加I / O延迟,增加协议开销等等。这不是自动路由,可以提高小规模系统的性能。)
您可能还有“超线程”核心而不是真正的核心,或者操作系统阻止您的JVM使用所有核心。
答案 2 :(得分:1)
如果CPU或等待IO是你的瓶颈,添加独立线程可以产生很大的不同。
如果您有共享资源是瓶颈,例如您的L3缓存,您的网络适配器,您的内核,添加线程将无济于事,因为CPU不是问题。实际上,通过增加开销会使情况更糟。
我的应用是轻量级的
在这种情况下,CPU不太可能成为您的问题,并且您看到加速超过1个CPU的速度非常快。很可能你正在加速RabbitMQ使用的CPU。理想情况下它应该更有效率,这不应该真正有用。恕我直言,更高效的消息传递解决方案并没有因多CPU而获得太多收益,因为它们不会成为CPU的瓶颈。
答案 3 :(得分:1)
不管怎样,你只使用4个核心。有很多可以阻止你通过加倍你的线程来阻止你的性能翻倍,但是从你的4线程成功中你已经超越了所有这些。我猜你的代码中有一个错误来引发8个线程并且它只启动4个。(即使使用超线程,你也会得到一些改进。即使遇到所有可能的问题,你我会得到一些改进。)否则,我将选择TJCrowder和Stephen C:我认为你真的没有8个核心。
我尝试使用不同数量的线程:3,5,6。看看有什么变化。我想你很快就会遇到这个问题。
公平对待Java:如果你编写线程安全的代码并避免瓶颈,它会很好地处理线程,因为你已经注意到从一个线程到4个。我总是发现开销成本微不足道。
答案 4 :(得分:0)
您的应用程序没有线性加速,因此,它没有良好的可扩展性。
为了保持增加所需的线程数,以确保正在处理的数据相应增长。对于固定数量的数据,由于创建线程的开销将超过线程的计算时间,因此线程(和/或核心)数量的增加将在某些时候收益递减。
请务必查看以下链接:
古斯塔夫森定律与阿赫达尔定律有很好的对比,所以我强烈建议你理解这篇文章。