【发布时间】:2012-12-18 21:33:08
【问题描述】:
在我的应用程序中,有几个服务在它们自己的线程上处理信息,当它们完成后,它们会将消息发布到下一个服务,然后继续在自己的线程上完成其工作。消息的移交是通过 LinkedBlockingQueue 完成的。切换通常需要 50-80 us(从将消息放入队列直到消费者开始处理消息)。 为了加快最重要服务的移交,我想使用繁忙的自旋而不是阻塞方法(我有 12 个处理器内核并希望将 3 个专用于这些重要服务)。 所以.. 我将 LinkedBlockingQueue 更改为 ConcurrentLinkedQueue
做了
for(;;)
{
Message m = queue.poll();
if( m != null )
....
}
现在.. 结果是第一个消息传递需要 1 us,但随后延迟在接下来的 25 次切换中增加,直到达到 500 us,然后延迟突然回到 1 us,并且开始增加.. 所以我有 25 次迭代的延迟周期,其中延迟从 1 us 开始,到 500 us 结束。 (消息每秒传递大约 100 次)
平均延迟为 250,这并不是我想要的性能提升。
我还尝试使用 LMAX Disruptor 环形缓冲区而不是 ConcurrentLinkedQueue。该框架在繁忙的自旋实现中具有自己的构建和完全不同的队列实现,但结果是相同的。所以我很确定这不是队列的错,也不是我滥用某些东西..
问题是……这到底是怎么回事?为什么我会看到这种奇怪的延迟周期?
干杯!!
【问题讨论】:
-
您是否跟踪产生空白的旋转周期数?也许延迟与线程调度程序有关。你如何确保线程拥有核心的 100% 所有权?
-
这听起来与调度程序有关。你在什么操作系统上运行它?
-
'消息每秒传递大约 100 次' - 那是 10 毫秒,对吗?因此,使用阻塞队列,50-80us 添加到 10ms。减少增加的延迟有那么重要吗?即使是这样,在队列弹出时旋转(与用于在推送/弹出对象时短暂保护队列的自旋锁不同)也是 CPU/内存带宽黑洞 - 没有希望。
-
#Marko,钓鱼者。是的,我也怀疑操作系统调度程序,我正在运行 windows 和 java,因此无法将核心分配给进程。我唯一能做的就是不要运行比我拥有的内核更多的线程。
-
#Martin,消息以 10 毫秒的间隔发布,但是对于一个要创建的事件进行处理并到达其目的地大约需要 10 毫秒。 500我们。其中涉及上述类型的 3 个上下文切换。所以多达一半的延迟仅由切换线程组成。是的,也许它是无望的.. :)
标签: java multithreading performance queue