7

短版在标题中。

长版:我正在开发一个使用 Java 进行科学优化的程序。程序的工作量可以分为并行和串行阶段——并行阶段意味着正在执行高度可并行化的工作。为了加速程序(它运行数小时/数天),我创建了与我正在使用的机器上的 CPU 内核数相等的线程数——通常是 4 或 8 个——并在它们之间分配工作。然后我在进入串行阶段之前启动这些线程并加入()它们。

到目前为止,一切都很好。困扰我的是,并行阶段的 CPU 利用率和加速远未接近“理论最大值”——例如,如果我有 4 个内核,我预计会看到 350-400% 的“利用率”(如顶部报告)但相反,它在 180 到 310 之间反弹。仅使用一个线程,我得到 100% 的 CPU 利用率。

我所知道的线程不能全速运行的唯一原因是: - 由于 I/O 阻塞 - 由于同步而阻塞

在我的并行线程中没有任何 I/O 发生,也没有任何同步——线程共享的唯一数据结构是只读的,并且是基本类型或(非并发)集合。所以我正在寻找其他解释。一种可能性是多个线程反复阻塞垃圾收集,但这似乎只在内存压力的情况下才有意义,而且我分配的内存远高于所需的最大堆空间。

任何建议,将不胜感激。

更新:以防万一有人好奇,经过更多调查后,我调整了代码以获得一般性能并看到更好的利用率,即使我所做的任何更改都与同步无关。然而,一些变化应该会导致更少的新堆分配,特别是我摆脱了一些迭代器临时盒装数字的使用(用于高性能 Java 计算的 CERN“Colt”库在这里很有用:它提供了像 IntArrayList 这样的集合, DoubleArrayList 等用于基本类型。)。所以我认为垃圾收集可能是罪魁祸首。

4

7 回答 7

5

所有图形操作都在一个单一的线程上运行。如果他们正在渲染到屏幕上,他们将有效地争夺对该线程的访问。

如果您在 Windows 上运行,那么无论如何,所有图形操作都在单个线程上运行。其他操作系统也有类似的限制。

实际上,有时很难获得线程工作者的适当粒度,有时很容易使它们变得太大或太小,这通常会使您对所有内核的使用率低于 100%。

如果您没有渲染太多 gui,那么最可能的罪魁祸首是您争夺的共享资源比您想象的要多。使用 jprofiler 之类的分析器工具很容易看到这一点。一些 VM 像 bea 的 jrockit 甚至可以直接告诉您这一点。

这是您不想凭猜测采取行动的地方之一。获取分析器!

于 2008-12-02T07:54:54.337 回答
4

首先,GC 不仅会在“内存压力的情况下”发生,而且会在 JVM 认为合适的任何时候发生(据我所知,这是不可预测的)。

其次,如果您的线程在堆中分配内存(您提到他们使用集合,所以我猜他们确实在堆中分配内存),您永远无法确定该内存当前是在 RAM 中还是在虚拟内存页面上(操作系统决定),因此对“内存”的访问可能会产生阻塞 I/O 访问!

最后,正如先前答案中所建议的那样,您可能会发现使用探查器检查发生的情况很有用(甚至 JMX 监控可能会在那里提供一些提示)。

我相信除非您提供更具体的(代码)信息,否则很难获得有关您的问题的进一步提示。

于 2008-12-02T08:46:16.013 回答
2

首先,我假设你没有在盒子上做任何其他重要的工作。如果你是,那显然会把事情搞砸。

如果你真的不分享任何东西,这听起来确实很奇怪。你能给我们更多关于代码真正在做什么的想法吗?

如果您将程序的 n 个副本作为不同的 Java 进程运行,而每个副本只使用一个线程,会发生什么情况?如果这完全使用了每个 CPU,那么至少我们知道它不会是操作系统的问题。说到操作系统,它在哪个操作系统上运行,哪个 JVM?如果您可以尝试不同的 JVM 和不同的操作系统,结果可能会提示您出了什么问题。

于 2008-12-02T09:11:34.307 回答
1

还有一点很重要:您使用哪种硬件?例如,4-8 核可能意味着您使用 Suns Niagara CPU 之一。尽管有 4-8 个核心,但它们的FPU更少。在计算科学数据时,可能会发生 FPU 是瓶颈。

于 2008-12-02T09:17:24.560 回答
0

您正在某种程度上进行同步。

也许只存在于内存分配系统中,包括垃圾收集。尽管 JVM 供应商已努力将这些区域的阻塞降至最低,但他们无法将其减少到零。也许您的应用程序的某些内容正在推动该领域的薄弱环节。

公认的智慧是“不要建立自己的内存回收池,让 GC 为你工作”。大多数情况下都是如此,但至少在我维护的一段代码中并非如此(通过分析证明)。也许您需要以某种主要方式重新设计您的对象分配。

于 2008-12-04T20:10:58.920 回答
0

您尝试使用完整的 CPU 功能进行计算,但操作系统本身也使用资源。因此请注意,操作系统会阻止您的某些执行以满足其需求。

于 2008-12-02T09:03:03.483 回答
0

试试 JRockit Mission Control 附带的延迟分析器。如果应用程序正在等待文件 I/O、TLA 获取、对象分配、线程挂起、JVM 锁、gc 暂停等,它将向您显示 CPU 在不做任何事情时正在做什么。您还可以查看转换,例如当一个线程唤醒另一个线程时。开销可以忽略不计,1% 左右。

有关更多信息,请参阅此博客。该工具可免费用于开发,您可以在此处下载

于 2008-12-10T02:33:16.010 回答