web-dev-qa-db-fra.com

Java 8: boucle FOR parallèle

J'ai entendu Java 8 fournit de nombreux utilitaires concernant l'informatique simultanée. Par conséquent, je me demande quel est le moyen le plus simple de paralléliser la boucle donnée?

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);
    }
}
60
Joe Inner

Lisez sur flux , ils sont tous la nouvelle rage.

Portez une attention particulière au parallélisme:

"Le traitement des éléments avec une boucle for explicite est intrinsèquement série. Les flux facilitent l'exécution parallèle en recadrant le calcul sous la forme d'un pipeline d'opérations d'agrégat, plutôt que d'opérations impératives sur chaque élément. Toutes les opérations de flux peuvent être exécutées en série ou en parallèle. "

Donc, pour récapituler, il n'y a pas de boucles for parallèles, elles sont intrinsèquement série. Les flux peuvent cependant faire le travail. Regardez le code suivant:

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

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

Ce serait en utilisant un Stream:

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

Je soupçonne qu'un Collector peut être utilisé plus efficacement ici, puisque vous utilisez une collection simultanée.

18
fge

Une solution plus élégante ou fonctionnelle utilisera simplement les fonctions Collectors toMap ou toConcurrentMap, qui évitent de conserver une autre variable stateful pour ConcurrentHashMap, comme dans l'exemple suivant:

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

Remarque: 1. Ces interfaces fonctionnelles (Server::getIdentifier or Server::fetchData) n'autorise pas l'exception de vérification vérifiée ici, 2. Pour tirer pleinement parti du flux parallèle, le nombre de serveurs serait important et aucune entrée/sortie n'est impliquée, il s'agit uniquement d'un traitement de données dans ces fonctions (getIdentifier, fetchData)

Veuillez vous reporter au javadoc de collecteurs à l’adresse http://docs.Oracle.com/javase/8/docs/api/Java/util/stream/Collectors.html#toConcurrentMap

5
zd333

Exemple simple pour copier/coller (les exemples ci-dessus utilisent la classe Server qui est une classe personnalisée écrite par l'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);
});

Sortie de la console. L'ordre peut éventuellement varier car tout s'exécute en parallèle:

Item1
Item2

La méthode .parallelStream() a été introduite dans Java v8. Cet exemple a été testé avec JDK v1.8.0_181.

1
Contango