14

我正在用 Java 实现一个工作池。

这本质上是一个完整的对象负载,它们将拾取数据块,处理数据,然后存储结果。由于 IO 延迟,worker 的数量将明显多于处理器内核。

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

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

假设为了争论一个四核 Linux 服务器,您预计这些解决方案中的哪个解决方案性能更高,为什么?

你可以假设工人永远不需要相互交流。

4

3 回答 3

18

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

在作业之间进行上下文切换时,在某些处理器上,在线程之间切换比在进程之间切换更便宜。这在这种 I/O 密集型情况下尤其重要,因为工作人员多于内核。您在 I/O 阻塞之间做的工作越多,这一点就越不重要。不过,良好的缓冲将为线程进程付费。

在同一 JVM 中的线程之间切换时,至少某些 Linux 实现(尤其是 x86)不需要刷新缓存。 请参阅 Tsuna 的博客。线程之间的缓存污染将被最小化,因为它们可以共享程序缓存,执行相同的任务,并共享相同的代码副本。我们谈论的是每个开关节省 100 纳秒到几微秒的量级。如果这对你来说是小土豆,那么请继续阅读......

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

线程的启动和预热时间通常要短得多。操作系统不必启动一个进程,Java 不必启动另一个 JVM,类加载只完成一次,JIT 编译只完成一次,HotSpot 优化完成一次,而且更快。

于 2011-10-26T13:51:12.407 回答
18

通常,当讨论多处理(每个进程一个线程)与同一进程中的多线程时,虽然第一种情况下的理论开销大于后者(因此多处理理论上比多线程慢),实际上,在大多数现代操作系统上,这并不是什么大问题。但是,在 Java 上下文中讨论它时,启动一个新进程的成本要比启动一个新线程高得多。启动一个新进程意味着启动一个新的 JVM 实例,这非常昂贵,尤其是在内存方面。我建议您在同一个 JVM 中启动多个线程。

此外,如果您说线程间通信不是问题,则可以使用Java的Executor Service来获得大小为2x(可用CPU数)的固定线程池。可用 CPU 的数量可以通过 Java 的 Runtime 类在运行时自动检测。这样,您无需任何样板代码即可获得快速简单的多线程。

于 2011-10-26T14:24:30.223 回答
1

实际上,如果您使用多个 jvm 进程对大规模任务执行此操作,则比一个具有多个线程的 jvm 快得多。至少我们从来没有让一个 jvm 运行得像多个 jvm 一样快。

我们做了一些计算,其中每个任务使用大约 2-3GB 内存并进行一些繁重的数字运算。如果我们生成 30 个 jvm 并运行 30 个任务,它们的性能比在一个 jvm 中生成 30 个线程要好 15-20%。我们尝试调整 gc 和各种内存部分,但从未赶上第一个变体。

我们在各种机器上执行此操作,16 核服务器上的 14 个任务,36 核服务器上的 34 个任务等。java 中的多线程总是比多个 jvm 进程执行 worde。

它可能对简单的任务没有任何影响,但在繁重的计算中,jvm 在线程上的性能似乎很差。

于 2017-05-06T10:42:58.363 回答