为什么此 Java 代码不利用所有 CPU 内核?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2867278/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why does this Java code not utilize all CPU cores?
提问by ReneS
The attached simple Java code should load all available cpu core when starting it with the right parameters. So for instance, you start it with
当使用正确的参数启动它时,附加的简单 Java 代码应该加载所有可用的 cpu 核心。因此,例如,您以
java VMTest 8 int 0
java VMTest 8 int 0
and it will start 8 threads that do nothing else than looping and adding 2 to an integer. Something that runs in registers and not even allocates new memory.
它将启动 8 个线程,除了循环并将 2 添加到一个整数之外什么都不做。在寄存器中运行甚至不分配新内存的东西。
The problem we are facing now is, that we do not get a 24 core machine loaded (AMD 2 sockets with 12 cores each), when running this simple program (with 24 threads of course). Similar things happen with 2 programs each 12 threads or smaller machines.
我们现在面临的问题是,当运行这个简单的程序(当然有 24 个线程)时,我们没有加载 24 核机器(AMD 2 个插槽,每个插槽有 12 个内核)。类似的事情发生在 2 个程序,每个程序 12 个线程或更小的机器上。
So our suspicion is that the JVM (Sun JDK 6u20 on Linux x64) does not scale well.
所以我们怀疑 JVM(Linux x64 上的 Sun JDK 6u20)不能很好地扩展。
Did anyone see similar things or has the ability to run it and report whether or not it runs well on his/her machine (>= 8 cores only please)? Ideas?
有没有人看到类似的东西或有能力运行它并报告它是否在他/她的机器上运行良好(请> = 8核)?想法?
I tried that on Amazon EC2 with 8 cores too, but the virtual machine seems to run different from a real box, so the loading behaves totally strange.
我也在 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);
}
}
回答by Marcus Adams
I don't see anything wrong with your code.
我看不出你的代码有什么问题。
However, unfortunately, you can't specify the processor affinity in Java. So, this is actually left up to the OS, not the JVM. It's all about how your OS handles threads.
但是,不幸的是,您无法在 Java 中指定处理器关联。所以,这实际上是由操作系统决定的,而不是 JVM。这完全取决于您的操作系统如何处理线程。
You could split your Java threads into separate processes and wrap them up in native code, to put one process per core. This does, of course, complicate communication, as it will be inter-process rather than inter-thread. Anyway, this is how popular grid computing applications like boink work.
您可以将 Java 线程拆分为单独的进程并将它们封装在本机代码中,以便每个内核放置一个进程。当然,这确实使通信复杂化,因为它将是进程间的而不是线程间的。无论如何,这就是像 boink 这样流行的网格计算应用程序的工作方式。
Otherwise, you're at the mercy of the OS to schedule the threads.
否则,您将受操作系统的支配来安排线程。
回答by Volker Stolz
I would guess this is inherent to the JVM/OS and not necessarily your code. Check the various JVM performance tuning docs from Sun, e.g. http://ch.sun.com/sunnews/events/2009/apr/adworkshop/pdf/5-1-Java-Performance.pdfwhich suggests using numactlon Linux to set the affinity.
我猜这是 JVM/OS 固有的,不一定是您的代码。检查来自 Sun 的各种 JVM 性能调整文档,例如http://ch.sun.com/sunnews/events/2009/apr/adworkshop/pdf/5-1-Java-Performance.pdf建议numactl在 Linux 上使用来设置亲和力。
Good luck!
祝你好运!
回答by johnidis
Apparently your VM is running in so-called "client" mode, where all Java threads are mapped to one native OS thread and consequently are run by one single CPU core. Try to invoke the JVM with -serverswitch, this should correct the problem.
显然,您的 VM 正在所谓的“客户端”模式下运行,其中所有 Java 线程都映射到一个本机操作系统线程,因此由一个 CPU 内核运行。尝试使用-serverswitch调用 JVM ,这应该可以解决问题。
If you get an: Error: no 'server' JVMfound, you'll have to copy the serverdirectory from a JDK's jre\bindirectory to JRE's bin.
如果找到:Error: no 'server' JVM找到,则必须将该server目录从 JDK 的jre\bin目录复制到 JRE 的bin.
回答by Nikhil
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
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
Intel(R) Xeon(R) CPU E5530 @ 2.40GHz http://browse.geekbench.ca/geekbench2/view/182101
Java 1.6.0_20-b02
Java 1.6.0_20-b02
16cores, the program consumed 100% cpu as shown by vmstat
16核,程序消耗了100%的cpu,如vmstat所示
Interestingly I came to this article because I am suspecting my application is not utilizing all the cores as the cpu utilisation never increases but the response time starts deteriorating
有趣的是,我来到这篇文章是因为我怀疑我的应用程序没有利用所有内核,因为 cpu 利用率从未增加,但响应时间开始恶化
回答by Bill K
I've noticed even on C that a tight loop often has issues like that. You'll also see pretty vast differences depending on OS.
我什至在 C 上也注意到紧密循环经常有这样的问题。根据操作系统的不同,您还会看到相当大的差异。
Depending on the reporting tool you are using, it may not report the CPU used by some core services.
根据您使用的报告工具,它可能不会报告某些核心服务使用的 CPU。
Java tends to be pretty friendly. You might try the same thing in linux but set the process priority to some negative number and see how it acts.
Java 往往非常友好。您可以在 linux 中尝试同样的事情,但将进程优先级设置为某个负数,然后看看它是如何运作的。
Setting thread priorities inside the app may help a little too if your jvm isn't using green threads.
如果您的 jvm 不使用绿色线程,则在应用程序内设置线程优先级也可能会有所帮助。
Lots of variables.
很多变数。

