为啥这段 Java 代码没有利用所有 CPU 内核?
Posted
技术标签:
【中文标题】为啥这段 Java 代码没有利用所有 CPU 内核?【英文标题】:Why does this Java code not utilize all CPU cores?为什么这段 Java 代码没有利用所有 CPU 内核? 【发布时间】:2011-02-21 11:25:26 【问题描述】:当使用正确的参数启动它时,附加的简单 Java 代码应该会加载所有可用的 cpu 内核。因此,例如,您以
开头java VMTest 8 int 0
它将启动 8 个线程,这些线程除了循环并将 2 加到一个整数之外什么都不做。在寄存器中运行甚至不分配新内存的东西。
我们现在面临的问题是,在运行这个简单的程序(当然是 24 线程)时,我们没有加载 24 核机器(AMD 2 个插槽,每个插槽有 12 个内核)。类似的事情发生在 2 个程序每个 12 个线程或更小的机器上。
所以我们怀疑 JVM(Linux x64 上的 Sun JDK 6u20)不能很好地扩展。
有没有人看到类似的东西或有能力运行它并报告它是否在他/她的机器上运行良好(请>= 8 核)?想法?
我也在 8 核的 Amazon EC2 上尝试过,但虚拟机的运行似乎与真实机器不同,因此加载行为非常奇怪。
package com.test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class VMTest
public class IntTask implements Runnable
@Override
public void run()
int i = 0;
while (true)
i = i + 2;
public class StringTask implements Runnable
@Override
public void run()
int i = 0;
String s;
while (true)
i++;
s = "s" + Integer.valueOf(i);
public class ArrayTask implements Runnable
private final int size;
public ArrayTask(int size)
this.size = size;
@Override
public void run()
int i = 0;
String[] s;
while (true)
i++;
s = new String[size];
public void doIt(String[] args) throws InterruptedException
final String command = args[1].trim();
ExecutorService executor = Executors.newFixedThreadPool(Integer.valueOf(args[0]));
for (int i = 0; i < Integer.valueOf(args[0]); i++)
Runnable runnable = null;
if (command.equalsIgnoreCase("int"))
runnable = new IntTask();
else if (command.equalsIgnoreCase("string"))
runnable = new StringTask();
Future<?> submit = executor.submit(runnable);
executor.awaitTermination(1, TimeUnit.HOURS);
public static void main(String[] args) throws InterruptedException
if (args.length < 3)
System.err.println("Usage: VMTest threadCount taskDef size");
System.err.println("threadCount: Number 1..n");
System.err.println("taskDef: int string array");
System.err.println("size: size of memory allocation for array, ");
System.exit(-1);
new VMTest().doIt(args);
【问题讨论】:
附加信息。刚刚发现 JDK 的 64 位版本加载内核的方式(大约 90%)比 32 位版本(大约 45%)更好。这很奇怪,因为操作系统和 AMD cpu 支持 32 位,而我在测试期间没有运行任何内存操作。 只是为了理解-为什么不使用 invokeAll(..) 方法?而且你为什么不使用可调用对象,据我所知,runnable 不是 java.concurrent 的一部分? 您还应该注意其他正在运行的进程。您是否进行了“干净”运行,没有其他程序/进程占用 CPU 时间? “int”任务的本机版本加载内核的能力如何? “字符串”/“int”有什么区别?发布一些汇总数字? @InsertNickHere:只是想快速编写代码以使用 Java 加载 cpus。只是为了证明一个理论。是的,这是一次干净利落的运行。 @Justin:我没有本机版本。它是关于检查Java是否可以在理论上处理核心和最简单的代码。 【参考方案1】:我看不出你的代码有什么问题。
但是,遗憾的是,您无法在 Java 中指定处理器亲和性。所以,这实际上是由操作系统决定的,而不是 JVM。这完全取决于您的操作系统如何处理线程。
您可以将 Java 线程拆分为单独的进程,然后将它们封装在本机代码中,从而为每个内核放置一个进程。当然,这确实使通信复杂化,因为它将是进程间而不是线程间的。无论如何,这就是像 boink 这样流行的网格计算应用程序的工作原理。
否则,您将任由操作系统来安排线程。
【讨论】:
这不是问题所在,运行 2 个具有较少线程的 VM 并不会对游戏产生太大影响。 每个内核运行一个JVM,每个有两个线程怎么样?您可能想更改您的问题,因为我回答了“为什么这段 Java 代码没有利用所有 CPU 内核?” 很抱歉造成误解,但问题是:“... THIS Java code...”。它很简单,没有锁定,没有同步,没有内存分配,仍然不是 100% 的 cpu 使用率。这应该会创建 X 个并发和独立的线程。【参考方案2】:我猜这是 JVM/OS 固有的,不一定是您的代码。查看 Sun 提供的各种 JVM 性能调整文档,例如http://ch.sun.com/sunnews/events/2009/apr/adworkshop/pdf/5-1-Java-Performance.pdf 建议在 Linux 上使用 numactl
来设置亲和力。
祝你好运!
【讨论】:
这个选项应该解决亲和力问题(如果实施) 感谢幻灯片和程序的提示。会试试的。 似乎做了一些事情,但它很棘手。还有一些额外的标志,例如 -XX:+UseTLAB 和 -XX:+UseNUMA 可以应用于 VM 以更好地使用底层架构。【参考方案3】:显然,您的 VM 正在所谓的“客户端”模式下运行,其中所有 Java 线程都映射到一个本地操作系统线程,因此由一个 CPU 内核运行。尝试使用-server
开关调用JVM,这应该可以解决问题。
如果找到:Error: no 'server' JVM
,则必须将 server
目录从 JDK 的 jre\bin
目录复制到 JRE 的 bin
。
【讨论】:
【参考方案4】:uname -a 2.6.18-194.11.4.el5 #1 SMP Tue Sep 21 05:04:09 EDT 2010 x86_64 x86_64 x86_64 GNU/Linux
Intel(R) Xeon(R) CPU E5530 @ 2.40GHz http://browse.geekbench.ca/geekbench2/view/182101
Java 1.6.0_20-b02
16cores,程序消耗了100%的cpu,如vmstat所示
有趣的是,我来到这篇文章是因为我怀疑我的应用程序没有利用所有内核,因为 CPU 利用率从未增加,但响应时间开始恶化
【讨论】:
【参考方案5】:即使在 C 语言上,我也注意到紧密循环经常会出现类似问题。您还会看到因操作系统而异的巨大差异。
根据您使用的报告工具,它可能不会报告某些核心服务使用的 CPU。
Java 往往非常友好。您可以在 linux 中尝试相同的操作,但将进程优先级设置为某个负数,然后查看它的作用。
如果您的 jvm 不使用绿色线程,在应用内设置线程优先级也可能会有所帮助。
很多变量。
【讨论】:
谢谢,但至少据我所知,在 Windows、Linux、Solaris、MacOS 等典型平台上,没有虚拟机使用绿色线程。 @ReneS 在过去的几年里,我一直在研究嵌入在有线电视盒和频谱分析仪中的 Java——我很少做这样的假设——我只是说有很多事情需要考虑。 没问题,感谢您的评论,只是很久没在我的 Java 世界中看到绿色线程了。以上是关于为啥这段 Java 代码没有利用所有 CPU 内核?的主要内容,如果未能解决你的问题,请参考以下文章
从 pandas 转移到 dask 以利用所有本地 cpu 核心