为什么这个Java代码没有利用所有的CPU核?
当使用正确的参数启动时,附带的简单Java代码应该加载所有可用的cpu内核。比如说,你从 java VMTest 8 int 0 它将启动8个线程,这些线程除了循环和向整数加2之外什么也不做。在寄存器中运行甚至不分配新内存的东西 我们现在面临的问题是,在运行这个简单的程序(当然有24个线程)时,我们没有加载24核的机器(AMD 2个插槽,每个插槽有12核)。类似的情况发生在2个程序中,每个程序有12个线程或更小的机器 因此,我们怀疑JVM(Linux x64上的Sun JDK 6u20)不能很好地扩展 是否有人看到类似的东西或有能力运行它,并报告它是否在他/她的机器上运行良好(请大于等于8个内核)?想法 我在AmazonEC2上也尝试过,它有8个内核,但是虚拟机的运行方式似乎与真实的机器不同,因此加载行为完全奇怪为什么这个Java代码没有利用所有的CPU核?,java,scalability,cpu,multicore,scaling,Java,Scalability,Cpu,Multicore,Scaling,当使用正确的参数启动时,附带的简单Java代码应该加载所有可用的cpu内核。比如说,你从 java VMTest 8 int 0 它将启动8个线程,这些线程除了循环和向整数加2之外什么也不做。在寄存器中运行甚至不分配新内存的东西 我们现在面临的问题是,在运行这个简单的程序(当然有24个线程)时,我们没有加载24核的机器(AMD 2个插槽,每个插槽有12核)。类似的情况发生在2个程序中,每个程序有12个线程或更小的机器 因此,我们怀疑JVM(Linux x64上的Sun JDK 6u20)不能很好
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);
}
}
package.com.test;
导入java.util.concurrent.ExecutorService;
导入java.util.concurrent.Executors;
导入java.util.concurrent.Future;
导入java.util.concurrent.TimeUnit;
公共类VMT测试
{
公共类IntTask实现可运行
{
@凌驾
公开募捐
{
int i=0;
while(true)
{
i=i+2;
}
}
}
公共类StringTask实现可运行
{
@凌驾
公开募捐
{
int i=0;
字符串s;
while(true)
{
i++;
s=“s”+整数值(i);
}
}
}
公共类ArrayTask实现可运行
{
私人最终整数大小;
公共阵列任务(整数大小)
{
这个。大小=大小;
}
@凌驾
公开募捐
{
int i=0;
字符串[]s;
while(true)
{
i++;
s=新字符串[大小];
}
}
}
公共void doIt(字符串[]args)引发InterruptedException
{
最后一个字符串命令=args[1]。trim();
ExecutorService executor=Executors.newFixedThreadPool(Integer.valueOf(args[0]);
对于(int i=0;i
我看不出你的代码有什么问题
然而,不幸的是,您不能在Java中指定处理器相关性。因此,这实际上取决于操作系统,而不是JVM。这一切都是关于你的操作系统如何处理线程
您可以将Java线程拆分为单独的进程,并用本机代码将它们包装起来,以便为每个核心放置一个进程。当然,这会使通信复杂化,因为这将是进程间通信,而不是线程间通信。无论如何,这就是像boink这样流行的网格计算应用程序的工作原理
否则,您就只能由操作系统安排线程了。我想这是JVM/OS固有的,不一定是您的代码。查看Sun提供的各种JVM性能调优文档,例如,其中建议在Linux上使用
numactl
来设置相关性
祝你好运 我注意到,即使是在C上,紧密循环也经常会出现类似的问题。您还将看到不同操作系统之间的巨大差异 根据您使用的报告工具,它可能不会报告某些核心服务使用的CPU Java往往非常友好。您可以在linux中尝试同样的方法,但将进程优先级设置为负数,然后查看它是如何工作的 如果您的jvm没有使用绿色线程,那么在应用程序中设置线程优先级也可能会有所帮助 很多变量。uname-a 2.6.18-194.11.4.el5#1 SMP周二9月21日05:04:09美国东部夏令时2010年x86_64 x86_64 x86_64 GNU/Linux 英特尔(R)至强(R)CPU E5530@2.40GHz Java 1.6.0_20-b02 16个内核,程序消耗100%的cpu,如vmstat所示
有趣的是,我之所以读这篇文章,是因为我怀疑我的应用程序没有利用所有的内核,因为cpu利用率从未增加,但响应时间开始恶化显然,您的虚拟机正在所谓的“客户端”模式下运行,所有Java线程都映射到一个本机OS线程,因此由一个CPU内核运行。尝试使用
-server
开关调用JVM,这将纠正问题
如果您得到一个:
错误:找不到“服务器”JVM
,您必须将server
目录从JDK的jre\bin
目录复制到jre的bin这不是问题,用较少的线程运行两个虚拟机不会对游戏产生太大的影响。每个核心运行一个JVM,每个核心运行两个线程如何?您可能想更改您的问题,因为我回答了“为什么此Java代码没有利用所有CPU内核?”对于误解,很抱歉,但问题是:“…此Java代码…”。它很简单,没有锁定,没有同步,没有内存