【发布时间】:2012-09-13 14:31:27
【问题描述】:
我有一个 Clojure 网络应用,基本结构是这样的:
- 服务器有一个 LinkedBlockingQueue 或 ArrayBlockingQueue(我都试过了)
- 多个线程接受网络连接,
offer工作到队列中 - 队列中的一个线程
take在无限循环中处理每个获取的项目
我注意到take 调用存在严重的性能问题:
- 线程以非常快的速度
offering 到队列中,并且队列很快将它们全部带走 - 一个工作线程
take从队列中以非常慢的速度(比offer的速度慢200多倍) - CPU 使用率非常低 - 所以工作人员根本不忙
在不使用队列的情况下,在基准测试情况下,相同的工作负载能够最大限度地利用 CPU 并以令人满意的速度完成。
那么在这种情况下,最好的排队技术是什么?
这是我的代码(少于 100 行);
https://github.com/HouzuoGuo/Aurinko/blob/master/src/Aurinko/core.clj
编辑,我的观察细节:
- 我对请求处理速度进行了基准测试,它在不使用队列的情况下以每秒大约 8,000 个请求的速度工作。
- 我让服务器程序在排队请求时打印一条调试消息,并在完成处理请求时打印另一条消息。
- 我制作了一个简单的客户端程序,每秒向服务器发送大约 1,000 个请求。
- 服务器及时将所有请求排队,队列变成数千个元素。
- 根据调试消息,Worker(请求处理器)似乎仅以每秒大约 150 个请求的速度工作。
编辑:
感谢大家的帮助。我已经确认阻塞队列不是导致性能问题的原因。虽然我没有发现我的应用程序的性能瓶颈,但一定有一个地方。
最终编辑:
谢谢大家。性能瓶颈是由网络 IO 而非阻塞队列引起的。
【问题讨论】:
-
我不确定您是如何测量延迟的,因为我无法阅读 clojure 但 take() 会根据需要等待。当队列确实为空时,这似乎会使 take() 变慢。
-
谢谢彼得。我知道
.take会阻塞直到元素可用。在我的场景中,有数千个请求排队(那些阻塞队列在排队请求时效果很好),但是与我在不使用队列的情况下处理负载的基准相比,.take的工作速度太慢了。 -
当你不使用队列时,这是唯一的改变还是你也在改变诸如如何使用线程之类的东西?
-
我需要两个特性:移除队列头部并阻塞直到元素可用;可以安全地从多个线程中删除并添加到队列中。我认为blockingqueue满足这两个要求,但如果我要使用java.util.queue,我需要手动管理它们
-
您能否演示一个简单的示例,其中使用队列会导致延迟,甚至是您所看到的延迟的一小部分,因为我不能,所以我不知道您为什么认为这是导致问题。