Многопоточность Java, лучший размер для пула в зависимости от ядер ЦП (виртуальный с многопоточностью и физический)

1

Я играю с многопроцессорными в Java (Sun JDK 1.7 64 бит), пытаясь понять некоторые концепции лучше. То, что я нахожу озадаченным, - это найти размер пула потоков для исполнителя и влияние этого параметра на производительность. Вот мой базовый код:

public class Program {

static int bestThreads = 0;
static long bestTime = Integer.MAX_VALUE;

public static void main(String[] args) throws InterruptedException, ExecutionException {

    int cores = Runtime.getRuntime().availableProcessors();

    for (int sizeOfPool = 1; sizeOfPool <= cores; sizeOfPool++) {
        ExecutorService exec = Executors.newFixedThreadPool(sizeOfPool);

        //System.out.println("Started");

        int noOftasks = 1000;
        for (int i = 0; i < noOftasks; i++) {
            Calculator c = new Calculator();
            exec.submit(c);
        }
        long start = System.currentTimeMillis();

        exec.shutdown();
        exec.awaitTermination(1000, TimeUnit.DAYS);

        long stop = (System.currentTimeMillis() - start);

        //System.out.println("Done " + noOftasks + " tasks in " + stop + " on " + sizeOfPool + " threads");

        if (bestTime > stop) {
            bestTime = stop;
            bestThreads = sizeOfPool;
        }

    }

    System.out.println("Best size of pool " + bestThreads + " result in " + bestTime + " ms");

}

public static class Calculator implements Runnable {

    @Override
    public void run() {
        doJob();
    }

}

//Can be whatever this just gives me a few milliseconds worth of CPU load since I don't want to use Thread.sleep()
public static void doJob() {
    for (int j = 0; j < 1E3; j++) {
        Math.round(Math.sin(Math.sqrt(Math.random())));

    }
}

Когда я запускаю эту программу, я получаю, что параметр, который использовал наименьшее количество времени, был тем, который использует N потоков, где N обычно 2 (что означает, что я должен использовать 2 потока для размера пула потоков). Я не понимаю, почему это происходит из-за того, что число процессоров, которые я получаю из.availableProcessors(), равно 4 (я использую i3 с многопоточным доступом, это на ноутбуке, а Windows показывает, что все потоки активны при запуске программы). Кроме того, я обычно получаю разные результаты, когда меняю количество выполненных работ:

1E1 → N = 4

1E2 → N = 3 или 2

1E3 → N = 2

1E4 → N = 2

но даже тогда в большинстве случаев я получаю N = 2;

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

Вот немного больше результатов, которые я нахожу странными:

Выполнено 1000 заданий в 195 на 1 потоке//Хорошо, для этого процессора требуется около 200 мс, чтобы перевести его с тактовой частотой, это поможет мне представить

Выполнено 1000 задач в 134 на 2 потоках//Я знаю, что я не могу увеличить 2x из-за переключения контекста и некоторых других воздействий на создание потоков, но это приятное ускорение

Сделано 1000 задач в 138 на 3 потоках//Почти так же, как 2 потока, почему это не хуже или лучше

Сделано 1000 задач в 210 на 4 потоках//Хуже, чем 1 поток, это тот, который я действительно не получаю

Теги:
multithreading
cpu
multicore

1 ответ

4
Лучший ответ

Ваше тестовое задание полностью связано с процессором, это означает, что он зависит только от частоты CPU/core. В то время как i3 утверждает, что имеет 4 ядра, это двухъядерный процессор (2 ядра с двумя потоками каждый, а также гиперпоточность).

Hyperthreading не дает вам 4 полных ядра, каждое ядро работает на любом из двух его потоков (оно автоматически переключается, например, когда поток ожидает доступа к памяти). Таким образом, в вашем тестовом примере процессор i3 лучше всего работает с двумя потоками, так как это максимум, который ваш процессор может обрабатывать (истинно) одновременно.

С другим тестом (например, с большим количеством обращений к памяти или ожиданием ввода-вывода) вы получите разные "идеальные" номера потоков.

Изменение: Я не знаю, как отличить реальное "физическое" ядро и "виртуальное" ядро в java. Новые процессоры AMD имеют свои собственные особенности в этом отношении (отдельные ядра, но FPU разделены между двумя ядрами), поэтому его действительно очень низкоуровневая технология зависит. Чтобы действительно получить все детали, вам, вероятно, потребуется прочитать идентификатор CPU и проверить лист данных для этого CPU.

Причина, по которой вы получаете когда-то 2, а иногда и 3, вероятно, связана с тем, что многопоточные тесты не являются действительно детерминированными (операционная система неизбежно будет потреблять некоторый процессор в произвольные моменты времени). Кроме того, краткосрочные тесты часто показывают много вариаций в java из-за прогрева JIT (ищите микробиблиотеку, ее сложную тему).

Вы должны видеть разницу между i3/i7 независимо.

  • 0
    Эта информация немного проясняет ситуацию, так что спасибо. Так что, если я запустил его на i7 (настоящие 4 ядра), я должен получить 4 в качестве ответа, верно? И есть ли в Java API, чтобы это как-то узнать? Есть ли у вас какой-нибудь намек, почему странные вещи случаются для небольшой работы и почему я получаю почти одинаковые результаты для 2 и 3 потоков.
  • 0
    @PSIXO Добавил некоторые объяснения

Ещё вопросы

Сообщество Overcoder
Наверх
Меню