Загрузка многоядерного процессора приложением Java

#java #multithreading #multicore #utilization

#java #многопоточность #многоядерный #использование

Вопрос:

У меня есть программа, которая сортирует большие файлы, разбивая их на фрагменты, сортируя фрагменты и объединяя их в окончательный отсортированный файл. Приложение запускает один поток для загрузки / сохранения данных из / в файл — только один поток выполняет операции ввода-вывода. Также есть еще два потока, которые получают фрагментные данные, сортируют их, а затем отправляют отсортированные данные обратно в поток, который выполняет ввод-вывод.

Таким образом, в целом выполняется 4 потока — основной поток, поток, который загружает / сохраняет данные, и два потока, которые сортируют данные.

Я думал, что во время выполнения я увижу 1 спящий поток (основной), который не требует никакого процессорного времени, и 3 активных потока, которые используют по 1 ядру процессора каждый.

Когда я запускаю эту программу на двухъядерном процессоре с 6 ядерными процессорами с hyper threading (24 процессора), я вижу, что ВСЕ 24 процессора загружены на 100%!

Изначально я думал, что алгоритм сортировки многопоточен, но после изучения источников Java я обнаружил, что это не так.

Я использую simple Collections.sort(LinkedList) для сортировки данных…

вот некоторые подробности:

# java -
версия версия java "1.6.0_26"
Среда выполнения Java (TM) SE (сборка 1.6.0_26-b03)
64-разрядная серверная виртуальная машина Java HotSpot (TM) (сборка 20.1-b02, смешанный режим)

# uname -a
Linux 2.6.32-28-server # 55-Ubuntu SMP Пн Янв 10 23:57:16 UTC 2011 x86_64 GNU / Linux

Я использовал nmon для мониторинга загрузки процессора.

Я был бы признателен за любое объяснение этого случая и любые советы о том, как контролировать загрузку процессора, поскольку эта конкретная задача не оставляет процессорного времени для других приложений

[ОБНОВЛЕНИЕ] Я использовал jvisualvm для подсчета потоков — он показывает только потоки, о которых я знаю. Также я создал простую тестовую программу (см. Ниже), которая запускает только один основной поток и получила точно такие же результаты — все 24 процессора заняты почти на 100% во время выполнения кода

 public class Test {

    public void run(){
        Random r = new Random();
        int len = r.nextInt(10)   5000000;
        LinkedList<String> list = new LinkedList<String>();
        for (int i=0; i<len; i  ){
                list.add(new String("test"   r.nextInt(50000000)));
        }
        System.out.println("Inserted "   list.size()   " items");
        list.clear();
    }

    public static void main(String[] argv){
        Test t = new Test();
        t.run();
        System.out.println("Done");
    }
}
  

[ОБНОВЛЕНИЕ]
Вот снимок экрана, который я сделал во время запуска программы выше (используется nmon):
http://imageshack.us/photo/my-images/716/cpuload.png /

Комментарии:

1. Вероятно, нам нужно просмотреть ваш код, чтобы понять это. Я предполагаю, что вы используете больше потоков, чем думаете.

2. Я использовал jvisualvm для подсчета потоков — он показывает только потоки, о которых я знаю. Также я создал простую тестовую программу, которая запускает только один основной поток и получила точно такие же результаты. пожалуйста, ознакомьтесь с моим обновлением, о котором идет речь.

3. 4 потока не могут использовать 100%-ную загрузку 6 ядер. Либо у вас больше потоков, либо ваши измерения неверны.

4. Какую программу вы используете для мониторинга загрузки процессора? Вероятно, он показывает вам какую-то другую программу, которая работает в фоновом режиме. Либо это, либо ваш тест настолько короткий, что он показывает вам только что-то, связанное с запуском JVM.

5. Я использовал nmon для мониторинга загрузки процессора, вот скриншот: ссылка Также, пока я не запускаю программу Java — она не показывает никакой активности. Во всяком случае, я вижу то же самое при запуске моей оригинальной программы сортировки. Честно говоря, я ожидал именно того, чего все ожидали бы — один поток использует один процессор. но похоже, что java использует зеленые потоки, которые не связаны с базовыми потоками ОС. Насколько я понимаю, java использует собственное планирование потоков. Таким образом, это может привести к тому, что несколько собственных потоков будут обслуживать один поток Java???

Ответ №1:

Я бы предположил, что это скорее вопрос nmon, чем Java, и чтобы решить его, я бы взглянул на top команду, которая предоставляет информацию об использовании процессора для каждого процесса. Я предсказываю следующий результат: вы увидите, что один поток Java использует около 100% процессорного времени (что нормально, поскольку процентное соотношение между процессами в top относительно одного (виртуального) ядра), возможно, второй и третий потоки Java с гораздо меньшим использованием ЦП (потоки ввода-вывода). В зависимости от выбора gc вы можете даже обнаружить один или несколько gc-потоков, однако намного меньше 20.

Однако HotSpot не будет (и даже не может, насколько мне известно) самостоятельно распараллеливать последовательную задачу.

Комментарии:

1. Я проверил приложение с помощью «top -H», и там было много потоков, принадлежащих java. Затем я проверил приложение с помощью «jstack» во время выполнения и обнаружил там большое количество потоков gc: «Поток задач GC # 0» …. «Поток задач GC # 14» Итак, я считаю, что загрузка, показанная nmon, была сгенерирована потоками GC. Я прочитаю больше о том, как управлять GC. @Jonathan спасибо, что вернулся с идеей GC, у тебя есть мой голос

2. Я использовал -XX:ParallelGCThreads для управления количеством потоков и получил точно ожидаемые результаты в nmon — 4 потока приложений использовали 4 ядра. @Джонатан, еще раз спасибо!