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);
}
}
Ответы
Ответ 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);
}
});
}