Ich bin neu in Java 8. Ich kenne die API noch nicht genau, aber ich habe einen kleinen informellen Benchmark erstellt, um die Leistung der neuen Streams-API mit den guten alten Sammlungen zu vergleichen.
Der Test besteht darin, eine Liste von zu filtern Integer
und für jede gerade Zahl die Quadratwurzel zu berechnen und in einem Ergebnis List
von zu speichern Double
.
Hier ist der Code:
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));
}.
Und hier sind die Ergebnisse für eine Dual-Core-Maschine:
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)
Für diesen speziellen Test sind Streams ungefähr doppelt so langsam wie Sammlungen, und Parallelität hilft nicht (oder verwende ich sie falsch?).
Fragen:
- Ist dieser Test fair? Habe ich einen Fehler gemacht?
- Sind Streams langsamer als Sammlungen? Hat jemand einen guten formalen Maßstab dafür gesetzt?
- Welchen Ansatz sollte ich anstreben?
Aktualisierte Ergebnisse.
Ich habe den Test 1k Mal nach dem Aufwärmen der JVM (1k Iterationen) ausgeführt, wie von @pveentjer empfohlen:
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)
In diesem Fall sind Streams leistungsfähiger. Ich frage mich, was in einer App zu beobachten wäre, in der die Filterfunktion zur Laufzeit nur ein- oder zweimal aufgerufen wird.
toList
sollte parallel ausgeführt werden, auch wenn es in einer nicht threadsicheren Liste erfasst wird , da die verschiedenen Threads vor dem Zusammenführen in threadbeschränkten Zwischenlisten erfasst werden.
IntStream
stattdessen mit einem versucht ?