Подтвердить что ты не робот

Java 8: Параллельный цикл FOR

Я слышал, что Java 8 предоставляет множество утилит для параллельных вычислений. Поэтому мне интересно, что является самым простым способом для параллелирования данного цикла?

public static void main(String[] args)
{
    Set<Server> servers = getServers();
    Map<String, String> serverData = new ConcurrentHashMap<>();

    for (Server server : servers)
    {
        String serverId = server.getIdentifier(); 
        String data = server.fetchData();

        serverData.put(serverId, data);
    }
}
4b9b3361

Ответ 1

Читайте на потоках, они все новые гнев.

Обратите особое внимание на бит около parallelism:

"Обработка элементов с явным циклом for-цикла по своей сути является последовательной. Потоки облегчают параллельное выполнение, перефразируя вычисление как конвейер агрегированных операций, а не как обязательные операции для каждого отдельного элемента. Все операции потоков могут выполняться либо в последовательном, либо в параллельно".

Итак, чтобы повторить, нет параллельных for-loops, они по сути являются серийными. Однако потоки могут выполнять эту работу. Взгляните на следующий код:

    Set<Server> servers = getServers();
    Map<String, String> serverData = new ConcurrentHashMap<>();

    servers.parallelStream().forEach((server) -> {
        serverData.put(server.getIdentifier(), server.fetchData());
    });

Ответ 2

Это будет использовать Stream:

servers.parallelStream().forEach(server -> {
    serverData.put(server.getIdentifier(), server.fetchData());
});

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

Ответ 3

Более элегантное или функциональное решение будет просто использовать функцию Collectors toMap или toConcurrentMap, что позволит избежать поддержки другой переменной с сохранением состояния для ConcurrentHashMap, как показано в следующем примере:

final Set<Server> servers = getServers();
Map<String, String> serverData = servers.parallelStream().collect(
    toConcurrentMap(Server::getIdentifier, Server::fetchData));

Примечание: 1. Эти функциональные интерфейсы (Server::getIdentifier or Server::fetchData) не допускают исключения с проверкой выброса здесь, 2. Чтобы получить все преимущества параллельного потока, количество серверов будет большим, и нет I/O участвует, чисто обработка данных в этих функциях (getIdentifier, fetchData)

Пожалуйста, обратитесь к коллекционерам Javadoc по адресу http://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html#toConcurrentMap

Ответ 4

Простой пример копирования'n'paste (в приведенных выше примерах используется класс Server который является пользовательским классом, написанным OP):

import java.io.Console;
import java.util.ArrayList;

ArrayList<String> list = new ArrayList<>();
list.add("Item1");
list.add("Item2");
list.parallelStream().forEach((o) -> {
    System.out.print(o);
});

Консольный вывод. Порядок может отличаться, поскольку все выполняется параллельно:

Item1
Item2

Метод .parallelStream() был представлен в Java v8. Этот пример был протестирован с JDK v1.8.0_181.

Ответ 5

используя мой Parallel.For, ваш код может выглядеть следующим образом:

public staic void main(String[] args)
{
    Set<Server> servers = getServers();
    Map<String, String> serverData = new ConcurrentHashMap<>();

    Parallel.ForEach(servers, new LoopBody<Server>()
    {
        public void run(Server server)
        {
             String serverId = server.getIdentifier(); 
             String data = server.fetchData();

             serverData.put(serverId, data);
        }
    });
}