我正在用Java实现一个工作池。
这基本上是一整堆对象,它们将获取数据块,处理数据然后存储结果。由于IO延迟,工作人员将远远多于处理器核心。
服务器专用于此任务,我想从硬件中获取最大性能(但不,我不想在C ++中实现它)。
最简单的实现是使用单个Java进程来创建和监视许多工作线程。另一种方法是为每个worker运行一个Java进程。
为了论证,假设有四核Linux服务器,您会预期这些解决方案中的哪一种更具性能?为什么?
您可以假设工人永远不需要彼此沟通。
答案 0 :(得分:18)
一个进程,多个线程 - 出于几个原因。
当在作业之间进行上下文切换时,某些处理器之间在线程之间切换比在进程之间切换更便宜。在这种I / O限制案例中,这一点尤为重要,因为工作人员多于核心。在阻止I / O之间做的工作越多,这一点就越不重要。但是,良好的缓冲将为线程或进程付出代价。
在同一JVM中的线程之间切换时,至少某些Linux实现(特别是x86)不需要刷新缓存。 See Tsuna's blog。线程之间的缓存污染将被最小化,因为它们可以共享程序缓存,执行相同的任务,并且共享相同的代码副本。我们说的是每个开关大约100纳秒到几微秒的节省。如果这对你来说是小土豆,请继续阅读...
根据设计,一个过程的I / O数据路径可能更短。
线程的启动和预热时间通常要短得多。操作系统不必启动进程,Java不必启动另一个JVM,类加载只执行一次,JIT编译只执行一次,HotSpot优化只执行一次,并且更快。
答案 1 :(得分:16)
通常情况下,在同一过程中讨论多处理(每个进程一个线程/多个线程)与多线程时相比,第一种情况下的理论开销大于后者(因此理论上多处理比多处理慢实际上在大多数现代操作系统中,这不是一个大问题。但是,在Java环境中讨论它时,启动新进程比启动新线程要昂贵得多。启动一个新进程意味着启动一个新的JVM实例,这个实例非常昂贵,特别是在内存方面。我建议您在同一个JVM中启动多个线程。
此外,如果您说线程间通信不是问题,您可以使用Java的Executor Service来获取大小为2x的固定线程池(可用CPU的数量)。可以通过Java的Runtime类在运行时自动检测可用CPU的数量。通过这种方式,您可以快速进行简单的多线程处理而无需任何样板代码。
答案 2 :(得分:0)
实际上,如果你使用多个jvm进程进行大规模删除比使用多个线程的jvm更快。至少我们从来没有像多个jvms那样快速运行一个jvm。
我们做了一些计算,其中每个任务使用大约2-3GB ram并进行一些重数字运算。如果我们产生30个jvm并执行30个任务,它们比在一个jvm中产生30个线程的性能提高约15-20%。我们尝试调整gc和各种内存部分,但从未赶上第一个变体。
我们在16核服务器上的各种机器14个任务,36核服务器上的34个任务上执行了此操作。在java中的多线程总是执行多个jvm进程。
它可能对简单任务没有任何影响,但是在繁重的计算中,似乎jvm在线程上表现不好。