Java性能:进程 vs 线程

14

我正在Java中实现工作池。

这本质上是一堆对象,它们将拾取数据块、处理数据并存储结果。由于IO等待时间很长,所以工作线程要比处理器核心多得多。

服务器专门用于此任务,我希望从硬件中获得最大的性能(但我不想用C++来实现)。

最简单的实现方法是有一个单独的Java进程创建和监视多个工作线程。另一种方法是为每个工作线程运行Java进程。

假设有一台四核Linux服务器,你预计哪种解决方案更具性能,为什么?

您可以假设工作线程永远不需要相互通信。

3个回答

18

一种进程,多个线程 - 几个原因。

在切换任务时,对于某些处理器来说,线程间的切换比进程间更加经济实惠。在这种I/O密集型情况下,工作线程数多于核心数尤其重要。您在受到I/O阻塞之前所做的工作越多,这一点就变得不那么重要了。然而,良好的缓存将为线程 进程付出努力。

在同一个JVM中切换线程时,至少一些Linux实现(特别是x86)不需要刷新缓存。请参见Tsun的博客。线程之间的缓存污染将被最小化,因为它们可以共享程序缓存,执行相同的任务,并共享代码的同一副本。我们在每次切换时节约100纳秒到几微秒的时间。如果这对您来说微不足道,请继续阅读...

根据设计,对于一个进程来说,I/O数据路径可能会更短。

线程的启动和预热时间通常更短。操作系统不需要启动进程,Java不需要启动另一个JVM,类加载只进行一次,JIT编译只进行一次,并且HotSpot优化只进行一次,并且更早。


1
在同一进程中的作业之间进行上下文切换并不比在进程之间进行上下文切换便宜得多——在现代CPU上,上下文切换的绝大部分成本来自于清空代码和数据缓存,这两种方式是相同的。如果一个设计有如此多的上下文切换,以至于上下文切换的性能很重要,那么这个设计就非常糟糕。 - David Schwartz
“在线程之间切换比进程之间切换更加经济实惠。”- 请问您能否提供一些支持这一论点的参考文献/基准测试数据。谢谢。 - NPE
另一个原因是Java为您提供了线程池、执行器服务和任务队列代码,以便轻松处理这种情况。 - Raedwald
@DavidSchwartz:在操作系统进程之间进行上下文切换将擦除处理器中的VM缓存,这将导致许多额外的内存访问到页面表。在线程之间进行上下文切换时不会发生这种情况,因为地址空间不会改变。但是如果您可以接受这一点,我喜欢操作系统进程方法,因为工作进程更加健壮,因为一个进程中的内存或其他资源泄漏不会影响其他进程。 - xpmatteo

18
通常情况下,当讨论多进程(每个进程一个线程)与同一进程内的多线程时,虽然前者的理论开销比后者大(因此多进程在理论上比多线程慢),但在大多数现代操作系统中,这并不是一个很大的问题。然而,在Java环境中讨论时,启动新进程比启动新线程要昂贵得多。启动新进程意味着启动JVM的新实例,这在内存方面特别昂贵。我建议您在同一JVM中启动多个线程。
此外,如果您说线程间通信不是问题,您可以使用Java的Executor Service来获得一个大小为2x(可用CPU数量)的固定线程池。可用CPU的数量可以通过Java的Runtime类在运行时自动检测到。这样,您就可以快速简单地进行多线程编程,而无需编写任何样板代码。

1
实际上,如果您使用多个jvm进程处理大规模任务,比使用一个带有多个线程的jvm要快得多。至少我们从未让一个jvm运行得像多个jvm一样快。
我们进行了一些计算,每个任务使用约2-3GB的内存并执行一些重度数值计算。如果我们生成30个jvm并运行30个任务,则它们的性能比在一个jvm中生成30个线程要好15-20%。我们尝试调整垃圾收集器和各种内存部分,但从未追赶上第一种变体。
我们在各种机器上进行了测试,在16核服务器上进行了14个任务,在36核服务器上进行了34个任务等。在Java中进行多线程始终表现不如多个jvm进程。
在简单任务上可能没有任何区别,但在重度计算上,似乎jvm在线程上表现不佳。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接