sentencia - Java 8: ciclo FOR paralelo
sentencia for en java eclipse (5)
Escuché 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 simple de paralelizar el ciclo 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);
}
}
Ejemplo simple para copiar y pegar (los ejemplos anteriores usan la clase
Server
que es una clase personalizada escrita por el 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);
});
Salida de consola. El orden podría variar ya que todo se ejecuta en paralelo:
Item1
Item2
El método
.parallelStream()
se introdujo en
Java v8
.
Este ejemplo fue probado con
JDK v1.8.0_181
.
Eso sería usar un
Stream
:
servers.parallelStream().forEach(server -> {
serverData.put(server.getIdentifier(), server.fetchData());
});
Sospecho que un
Collector
se puede utilizar para un mayor efecto aquí, ya que utiliza una colección concurrente.
Lea sobre las streams , son toda la nueva rabia.
Presta especial atención al bit sobre paralelismo:
"El procesamiento de elementos con un bucle for explícito es inherentemente serial. Los flujos facilitan la ejecución paralela al reenmarcar el cálculo como una tubería de operaciones agregadas, en lugar de operaciones imperativas en cada elemento individual. Todas las operaciones de flujos pueden ejecutarse en serie o en paralelo. "
En resumen, 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());
});
Una solución más elegante o funcional será simplemente usar Collectors toMap o 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 lanzar una excepción marcada aquí, 2. Para obtener todos los beneficios del flujo paralelo, el número de servidores sería grande y no hay I / O involucrado, puramente procesamiento de datos en esas funciones (
getIdentifier, fetchData
)
Consulte Collector javadoc en http://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html#toConcurrentMap
usando mi Paralelo. Para, su código podría ser similar al 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);
}
});
}