Почему этот Java кодирует не, используют все ядра процессора?

Приложенный простой код Java должен загрузить все доступное ядро CPU при запуске его с правильных параметров. Так, например, Вы запускаете его с

интервал java VMTest 8 0

и это запустит 8 потоков, которые не делают ничего иного, чем цикличное выполнение и добавление 2 к целому числу. Что-то, что работает в регистрах и даже не выделяет новую память.

Проблема, с которой мы сталкиваемся теперь, что мы не получаем 24 базовых загруженные машины (сокеты AMD 2 12 ядрами каждый) при запущении этой простой программы (с 24 потоками, конечно). Подобные вещи происходят с 2 программами каждого 12 потоков или машины меньшего размера.

Таким образом, наше подозрение - то, что JVM (Sun JDK 6u20 на Linux x64) не масштабируется хорошо.

Кто-либо видел подобные вещи или имеет способность выполнить ее и сообщить, работает ли она хорошо на его машине (> = 8 ядер только)? Идеи?

Я попробовал это на Amazon EC2 с 8 ядрами также, но виртуальная машина, кажется, работает отличающийся от реального поля, таким образом, загрузка ведет себя полностью странная.

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);
    }
}
14
задан Robert Harvey 19 May 2010 в 16:08
поделиться

3 ответа

Я не вижу ничего плохого в вашем коде.

Однако, к сожалению, вы не можете указать привязку к процессору в Java. Таким образом, это фактически оставлено на усмотрение ОС, а не JVM. Все дело в том, как ваша ОС обрабатывает потоки.

Вы можете разделить потоки Java на отдельные процессы и заключить их в собственный код, чтобы разместить по одному процессу на ядро. Это, конечно, усложняет общение, так как оно будет межпроцессным, а не межпоточным. Во всяком случае, именно так работают популярные приложения для грид-вычислений, такие как boink.

В противном случае, планирование потоков зависит от вас.

10
ответ дан 1 December 2019 в 13:47
поделиться

Я предполагаю, что это присуще JVM / OS и не обязательно вашему коду. Ознакомьтесь с различными документами по настройке производительности JVM от Sun, например http://ch.sun.com/sunnews/events/2009/apr/adworkshop/pdf/5-1-Java-Performance.pdf , в котором предлагается использовать numactl в Linux для установить близость.

Удачи!

4
ответ дан 1 December 2019 в 13:47
поделиться

Я заметил, что даже на C тугой цикл часто вызывает подобные проблемы. Вы также увидите довольно большие различия в зависимости от ОС.

В зависимости от инструмента отчетности, который вы используете, он может не сообщать о CPU, используемом некоторыми службами ядра.

Java, как правило, довольно дружелюбна. Вы можете попробовать сделать то же самое в linux, но установить приоритет процесса на какое-то отрицательное число и посмотреть, как он себя поведет.

Установка приоритетов потоков внутри приложения тоже может немного помочь, если ваша jvm не использует зеленые потоки.

Много переменных.

0
ответ дан 1 December 2019 в 13:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: