我正在并行处理一个递归函数,并且测得不良的加速比。在调试代码时,我注意到在顺序版本中,所有内核都可以正常工作。
在一个最小的示例中,我重现了这种行为,同样,我所有的内核的工作量约为90%。我正在使用Java 8(OpenJDK)。
Java是否在我不知情的情况下自动进行并行处理? Java如何做到这一点?
import java.util.Random;
import java.util.ArrayList;
class Node
{
float value;
ArrayList<Node> children;
public Node()
{
children = new ArrayList<Node>();
}
public Node(float value)
{
this.value = value;
}
public int count()
{
int count = 1;
if (children != null)
for (Node c : children)
count += c.count();
return count;
}
}
public class ProofOfConcept {
final static int N_NODES = 10000000;
final static int MAX_CHILDREN = 6;
final static Random RAND = new Random();
static Node generateTree(int nNodes)
{
if (nNodes > 1)
{
Node result = new Node();
int nChildren = 1 + RAND.nextInt(Math.min(MAX_CHILDREN, nNodes) - 1);
int nNodesPerChild = (nNodes - 1) / nChildren;
for (int i = 0; i < nChildren; ++i)
{
Node t = generateTree(nNodesPerChild);
result.children.add(t);
}
return result;
}
else
return new Node(RAND.nextFloat());
}
public static void main(String[] args)
{
Node t = generateTree(N_NODES);
System.out.println(t.count());
}
}
编辑:这对我来说真的也很奇怪。我附上了htop的屏幕快照;如您所见,我们有主进程和八个线程(每个逻辑内核一个)。
编辑2:似乎GC正在并行执行其工作。对于那些不明白为什么如果显然没有任何对象被释放的情况下触发GC的人,您应该阅读following reference:
当分配失败触发垃圾回收,但是垃圾回收没有释放足够的空间时,垃圾回收器将扩展存储堆。在堆扩展期间,垃圾收集器将从为堆保留的最大存储量(由-Xmx选项指定的量)中获取存储,并将其添加到堆的活动部分(从-指定的大小开始) Xms选项)。堆扩展不会增加JVM所需的存储量,因为-Xmx选项指定的最大存储量已在启动时分配给JVM。如果-Xms选项的值在堆的活动部分为应用程序提供了足够的存储空间,则垃圾收集器完全不必进行堆扩展。
答案 0 :(得分:6)
不,Java并非神奇地使您的代码并行化。
如果看到所有核心上的利用率都达到90%,则是操作系统,其他进程或JVM在做后台工作。可能是使用并行GC并利用所有内核收集垃圾的JVM。