Несоответствие времени обработки параллельных потоков Java

На моей машине с Windows у меня 6 ядер.

Я создаю поток из 24 элементов и выполняю операцию над каждым элементом, используя операцию карты в Stream API. Я использую параллелизм:

myCollection.parallelStream()
                    .map(element -> someTimeConsumingOperation(element)
                    .collect(toList());

someTimeConsumingOperation имитирует длительную операцию, используя:

Thread.sleep(2000);

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

Поскольку есть 6 ядер, я предполагаю, что создается максимум 6 потоков. Если это так, и каждая операция занимает почти 2 секунды, вся обработка потока должна занять около 8 секунд (каждый поток будет выполнять 4 операции, поскольку у нас есть 24 элемента для обработки, следовательно, 4 * 2 секунды).

Но я наблюдаю, что обработка занимает всего 4 секунды.


person Mandroid    schedule 03.08.2020    source источник
comment
Ваш процессор от Intel, и у вас включена гиперпоточность? (Если вы явно не выключили его, он включен)   -  person Joni    schedule 03.08.2020
comment
Метод sleep() в классе Thread выдает InterruptedException. Вы уверены, что каждая трудоемкая операция выполняется ровно две секунды?   -  person Abra    schedule 03.08.2020
comment
Я вижу, что есть что-то под названием «Логические процессоры», и его значение равно 12. Таким образом, с 24 элементами время составляет 4 секунды, а с 25 элементами время составляет 6 секунд. Это наблюдение соответствует числу логических процессоров (12). Я думаю, это объясняет, хотя и не уверен.   -  person Mandroid    schedule 03.08.2020


Ответы (1)


В вашем 6-ядерном процессоре Intel включена HyperThreading. При HT операционная система и приложения видят каждое ядро ​​ЦП как 2 отдельных логических ядра или потока (номенклатура различается). Это означает, что ForkJoinPool будет использовать 12 потоков вместо 6.

Логические ядра делят некоторые ресурсы друг с другом, поэтому параллельное выполнение 12 задач не дает вдвое большей пропускной способности, чем выполнение 6 задач. Но программа, которая вызывает только sleep(), не заметит разницы.

person Joni    schedule 04.08.2020