最小化Java线程上下文切换开销

时间:2010-05-28 05:57:40

标签: java performance multithreading solaris threadpool

我在Sun 1.6 32位VM / Solaris 10(x86)/ Nahelem 8核(每个核心2个线程)上运行Java应用程序。

应用程序中的特定用例是响应某些外部消息。在我的性能测试环境中,当我准备并在接收外部输入的同一线程中发送响应时,我获得大约50美元的优势,而不是当我将消息传递给单独的线程来发送响应时。我使用ThreadPoolExecutorSynchronousQueue进行切换。

根据您的经验,将任务安排到线程池并将其拾取执行之间的可接受的预期延迟是什么?过去有什么想法可以改善这一点?

4 个答案:

答案 0 :(得分:12)

“可接受的延迟”完全取决于您的申请。如果您有非常严格的延迟要求,那么处理同一线程上的所有内容确实会有所帮助。幸运的是,大多数应用程序没有那么严格的要求。

当然,如果只有一个线程能够接收请求,那么绑定该线程以计算响应将意味着您无法接受任何其他请求。根据您正在做的事情,您可以使用异步IO(etc)来避免“每个请求的线程”模型,但它的IMO要难得多,并且最终仍然会进行线程上下文切换。

有时排队请求是合适的,以避免有太多的线程处理它们:如果你的处理受CPU限制,那么拥有数百个线程没有多大意义 - 最好有一个生产者/消费者队列的任务和每个核心大约一个线程分发它们。这基本上是ThreadPoolExecutor当你正确设置它时会做的事情。如果您的请求花费大量时间等待外部服务(包括磁盘,但主要是其他网络服务),那么这也不会有效......此时您需要使用异步执行模型,无论何时您可能会创建一个使用阻塞调用进行核心空闲,或者你采用线程上下文切换命中并拥有大量线程,依靠线程调度程序使其运行良好。

底线是延迟要求可能很难 - 根据我的经验,它们比吞吐量要求更加困难,因为它们更难以扩展。它确实取决于上下文。

答案 1 :(得分:2)

对于切换,50us听起来有点高,IME(Solaris 10 / Opteron)LBQ通常在30-35us范围内,而LTQ(LinkedTransferQueue)比这快约5us。正如其他回复中所述,SynchronousQueue可能会略微变慢,因为要约在其他线程采取之前不会返回。

根据我的结果,Solaris 10在这方面明显慢于Linux,其时间<10us。

在峰值负荷下,这实际上取决于一些事情

  • 您每秒服务的请求数量是多少?
  • 处理请求通常需要多长时间?

如果您知道这些Q的答案,那么就性能而言,应该相当清楚,您是应该处理接收线程还是切换到处理线程。

答案 2 :(得分:1)

是否有理由不使用LinkedBlockingQueue,因此您的制作人可以排队几个项而不是SynchronousQueue?至少有一个包含1个项目的队列,这样你就可以获得更好的并行性。

“准备”流程与“响应”的速度是多少?你是否可以使用线程池让多个线程处理响应,如果它们太贵了?

答案 3 :(得分:0)

不是同一个任务,但是“是” - 队列通常用于时间关键任务。我们集中精力避免同步处理事件。查看以下提示

  • 不要使用同步容器(数组,列表,映射......)。想想每个线程的容器。
  • 我们使用了循环线程池。此池由预先分配的线程和(!)完全一个侦听事件组成,没有任何队列。当事件引发时,线程从循环中删除,另一个成为监听器。处理完成后,线程返回池中。