Java 8: Paralelo PARA bucle


He oído que Java 8 proporciona muchas utilidades con respecto a la computación concurrente. Por lo tanto, me pregunto cuál es la forma más sencilla de paralelizar el bucle for dado.

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);
    }
}
Author: Joe Inner, 2014-12-19

4 answers

Leer en corrientes, son todos la nueva moda.

Preste especial atención a la parte sobre el paralelismo:

"Procesar elementos con un bucle for explícito es inherentemente serial. Los flujos facilitan la ejecución paralela al replantear el cálculo como una canalización de operaciones agregadas, en lugar de como operaciones imperativas en cada elemento individual. Todas las operaciones de flujos pueden ejecutarse en serie o en paralelo."

Así que para recapitular, no hay bucles for paralelos, son inherentemente seriales. Sin embargo, las transmisiones pueden hacer el trabajo. Echa un vistazo al siguiente código:

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

    servers.parallelStream().forEach((server) -> {
        serverData.put(server.getIdentifier(), server.fetchData());
    });
 64
Author: A Boschman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-05 11:45:19

Que sería usar un Stream:

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

Sospecho que un Collector se puede usar con mayor efecto aquí, ya que usa una colección concurrente.

 14
Author: fge,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-19 01:53:04

Una solución más elegante o funcional será simplemente usar los colectores toMap o la función toConcurrentMap, que evitan mantener otra variable con estado para ConcurrentHashMap, como el siguiente ejemplo:

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

Nota: 1. Esas interfaces funcionales (Server::getIdentifier or Server::fetchData) no permiten la excepción marcada de tiro aquí, 2. Para obtener todos los beneficios de parallel stream, el número de servidores sería grande y no hay E/S involucradas, puramente procesamiento de datos en esas funciones(getIdentifier, fetchData)

Por favor consulte Coleccionistas javadoc en http://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html#toConcurrentMap

 4
Author: zd333,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-13 19:58:10

Usando mi Paralelo.Para, su código podría verse como el siguiente,

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);
        }
    });
}     
 -2
Author: Weimin Xiao,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-08 07:28:24