Распараллеливание Java с использованием лямбда-функций

У меня есть массив некоторых объектов с методом process (), который я хочу запустить распараллеливанием. И я хотел попробовать лямбды, чтобы добиться распараллеливания. Итак, я попробовал это:

Arrays.asList(myArrayOfItems).forEach(item->{
    System.out.println("processing " + item.getId());
    item.process();
});

Каждый вызов process () занимает около 2 секунд. И я заметил, что при «распараллеливании» все еще нет ускорения. Кажется, что все еще сериализовано. Идентификаторы печатаются последовательно (по порядку), и между каждым отпечатком делается пауза в 2 секунды.

Наверное, я что-то неправильно понял. Что необходимо, чтобы выполнить это параллельно с использованием лямбда-выражений (надеюсь, в очень сжатой форме)?

Вы имели в виду .parallelStream().forEach(item -> {..

YCF_L 16.03.2018 14:03

Спасибо, parallelStream () решил мою проблему

Azure 16.03.2018 14:08
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
2
810
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Метод Collection.forEach () - это просто итерация по всем элементам. Он называется внутренняя итерация, поскольку он оставляет до коллекции как, которую он будет повторять, но это все еще итерация для всех элементов.

Если вам нужна параллельная обработка, вам необходимо:

  1. Получите параллельный поток из коллекции.
  2. Укажите операции, которые будут выполняться в потоке.
  3. Если нужно, сделайте что-нибудь с результатом.

Вы можете прочитать первую часть моего объяснения здесь: https://stackoverflow.com/a/22942829/2886891

Чтобы создать параллельный поток, вызовите операцию .parallelStream в Коллекции.

См. https://docs.oracle.com/javase/tutorial/collections/streams/parallelism.html

Arrays.asList(myArrayOfItems).parallelStream().forEach(item->{
    System.out.println("processing " + item.getId());
    item.process();
});
Ответ принят как подходящий

Сами лямбды ничего не выполняют параллельно. Однако Stream способны на это.

Взгляните на метод Collection#parallelStream (документация):

Arrays.asList(myArrayOfItems).parallelStream().forEach(...);

Однако обратите внимание, что нет никакой гарантии или контроля, когда он действительно будет идти параллельно. Из его документации:

Returns a possibly parallel Stream with this collection as its source. It is allowable for this method to return a sequential stream.

Причина проста. Вам действительно нужно много элементов в вашей коллекции (например, миллионы) для того, чтобы распараллеливание действительно окупилось (или для выполнения других тяжелых вещей). Накладные расходы, связанные с распараллеливанием, составляют огромный. Из-за этого метод может вместо этого использовать последовательный поток, если считает, что он будет быстрее.

Прежде чем вы подумаете об использовании параллелизма, вам следует установить несколько тестов, чтобы проверить, улучшает ли он что-либо. Есть много примеров, когда люди просто слепо использовали его, не замечая, что они на самом деле снизили производительность. Также см. Должен ли я всегда использовать параллельный поток, когда это возможно?.


Вы можете проверить, параллелен ли Stream, используя Stream#isParallel (документация).

Если вы используете Stream#parallel (документация) непосредственно в потоке, вы получаете параллельную версию.

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

Azure 16.03.2018 14:16

Это верно. Просто обратите внимание, что параллелизм приводит к огромным накладным расходам, и вы не должны слепо использовать его везде, не задумываясь об этом или фактически измеряя время.

Zabuzard 16.03.2018 14:18

заказное исполнение в моем случае не требуется

Azure 16.03.2018 14:19

Другие вопросы по теме