Soy nuevo en Java 8. Todavía no conozco la API en profundidad, pero he hecho un pequeño punto de referencia informal para comparar el rendimiento de la nueva API de Streams con las colecciones antiguas.
La prueba consiste en filtrar una lista de Integer
, y para cada número par, calcular la raíz cuadrada y almacenarla como resultado List
de Double
.
Aquí está el código:
public static void main(String[] args) {
//Calculating square root of even numbers from 1 to N
int min = 1;
int max = 1000000;
List<Integer> sourceList = new ArrayList<>();
for (int i = min; i < max; i++) {
sourceList.add(i);
}
List<Double> result = new LinkedList<>();
//Collections approach
long t0 = System.nanoTime();
long elapsed = 0;
for (Integer i : sourceList) {
if(i % 2 == 0){
result.add(Math.sqrt(i));
}
}
elapsed = System.nanoTime() - t0;
System.out.printf("Collections: Elapsed time:\t %d ns \t(%f seconds)%n", elapsed, elapsed / Math.pow(10, 9));
//Stream approach
Stream<Integer> stream = sourceList.stream();
t0 = System.nanoTime();
result = stream.filter(i -> i%2 == 0).map(i -> Math.sqrt(i)).collect(Collectors.toList());
elapsed = System.nanoTime() - t0;
System.out.printf("Streams: Elapsed time:\t\t %d ns \t(%f seconds)%n", elapsed, elapsed / Math.pow(10, 9));
//Parallel stream approach
stream = sourceList.stream().parallel();
t0 = System.nanoTime();
result = stream.filter(i -> i%2 == 0).map(i -> Math.sqrt(i)).collect(Collectors.toList());
elapsed = System.nanoTime() - t0;
System.out.printf("Parallel streams: Elapsed time:\t %d ns \t(%f seconds)%n", elapsed, elapsed / Math.pow(10, 9));
}.
Y aquí están los resultados para una máquina de doble núcleo:
Collections: Elapsed time: 94338247 ns (0,094338 seconds)
Streams: Elapsed time: 201112924 ns (0,201113 seconds)
Parallel streams: Elapsed time: 357243629 ns (0,357244 seconds)
Para esta prueba en particular, las transmisiones son aproximadamente el doble de lentas que las colecciones, y el paralelismo no ayuda (¿o lo estoy usando de manera incorrecta?).
Preguntas:
- ¿Es justa esta prueba? ¿He cometido algún error?
- ¿Las transmisiones son más lentas que las colecciones? ¿Alguien ha hecho un buen punto de referencia formal sobre esto?
- ¿Por qué enfoque debería luchar?
Resultados actualizados
Ejecuté la prueba 1k veces después del calentamiento JVM (1k iteraciones) según lo aconsejado por @pveentjer:
Collections: Average time: 206884437,000000 ns (0,206884 seconds)
Streams: Average time: 98366725,000000 ns (0,098367 seconds)
Parallel streams: Average time: 167703705,000000 ns (0,167704 seconds)
En este caso, las secuencias son más efectivas. Me pregunto qué se observaría en una aplicación donde la función de filtrado solo se llama una o dos veces durante el tiempo de ejecución.
toList
debe ejecutarse en paralelo, incluso si se recopila en una lista no segura para subprocesos, ya que los diferentes subprocesos se recopilarán en listas intermedias confinadas en subprocesos antes de fusionarse.
IntStream
en su lugar?