Почему время выполнения java.util.Collection#parallelStream не соответствует ожиданию?
Результат cost
около 30, ожидайте 10.
private void process(int i) {
try {
Thread.sleep(10000); // 10s
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Test
public void testPartition() {
List<Integer> numbers = IntStream.range(1, 21).boxed().collect(Collectors.toList());
long cost = 0L;
long jobStart = System.currentTimeMillis();
numbers.parallelStream().forEach(x -> {
process(x);
});
cost += (System.currentTimeMillis() - jobStart);
System.out.println("availableProcessors = " + Runtime.getRuntime().availableProcessors());
System.out.println("cost = " + cost);
}
Кажется пробегает process(x);
3 раза. почему это?
@daniu прав.
ForkJoinPool в Java использует номер потока по умолчанию, равный количеству доступных процессоров, как сообщает метод Runtime.getRuntime().availableProcessors(). Эта конструкция предназначена для эффективного использования доступных ресурсов ЦП для задач параллельной обработки.
выход:
availableProcessors = 8
cost = 30015
Ожидаете ли вы, что он запустит 20 разных потоков? Почему вы так думаете?
еще лучше включить минимально воспроизводимый пример в такие вопросы... например. мы не знаем, что такое Lists
(конечно, мы можем это предположить)
Спасибо @daniu. parallelStream
использует значение по умолчанию ForkJoinPool
. ForkJoinPool в Java использует номер потока по умолчанию, равный количеству доступных процессоров.
availableProcessors = 8
тогда 20/8=3
, поэтому стоимость около 30, а не 10.
Кстати, вы можете изменить количество потоков, позвонив ForkJoinPool.commonPool().setParallelism(20)
— это должно привести к значению около 10 с для опубликованного кода.
@user85421 user85421 – Если вы используете VirtualThreads, это весьма вероятно. Но что касается аппаратных потоков, я бы сказал, что это зависит от ОС и оборудования. Из Javadoc для Thread::sleep
: «Нетка не теряет право собственности ни на один монитор». В некоторых средах это также означает, что ядро не будет освобождено. На моем компьютере с Unix оно было близко к 10, на моем NXT — выше 400 (хорошо, реализация Java на последнем в лучшем случае плохая).
Вероятно, это не имеет значения, но что заставляет вас говорить «использование одного потока»? По умолчанию
parallelStream
использует стандартныйForkJoinPool
IIRC. Почему вы объявляетеlong[]
, а затем используете только первый элемент для суммирования времени?