Я распараллеливаю рекурсивную функцию и измерил плохое ускорение. При отладке кода я заметил, что в последовательной версии все ядра работают.
Я воспроизвел это поведение в минимальном примере, и опять-таки, все мои ядра загружены примерно на 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 запускается, если очевидно, что никакие объекты не освобождаются, вы должны прочитать следующую ссылку :
Когда сборщик мусора запускается из-за сбоя выделения, но сборщик мусора не освобождает достаточно места, сборщик мусора расширяет кучу хранилища. Во время расширения кучи сборщик мусора извлекает хранилище из максимального объема хранилища, зарезервированного для кучи (объем, указанный параметром -Xmx), и добавляет его в активную часть кучи (которая начинается с размера, указанного в параметре - Вариант хмс). Расширение кучи не увеличивает объем памяти, требуемый для JVM, поскольку максимальный объем памяти, указанный параметром -Xmx, уже был выделен JVM при запуске. Если значение параметра -Xms обеспечивает достаточное хранилище в активной части кучи для ваших приложений, сборщик мусора вообще не должен выполнять расширение кучи.