Je suis nouveau sur Java 8. Je ne connais toujours pas l'API en profondeur, mais j'ai fait un petit benchmark informel pour comparer les performances de la nouvelle API Streams avec les bonnes anciennes Collections.
Le test consiste à filtrer une liste de Integer
, et pour chaque nombre pair, calculer la racine carrée et la stocker dans un résultat List
deDouble
.
Voici le 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));
}.
Et voici les résultats pour une machine dual core:
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)
Pour ce test particulier, les flux sont environ deux fois plus lents que les collections, et le parallélisme n'aide pas (ou je l'utilise de la mauvaise manière?).
Des questions:
- Ce test est-il juste? Ai-je fait une erreur?
- Les flux sont-ils plus lents que les collections? Quelqu'un a-t-il fait une bonne référence formelle à ce sujet?
- Quelle approche dois-je miser?
Résultats mis à jour.
J'ai exécuté le test 1k fois après le préchauffage de la JVM (1k itérations) comme conseillé par @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)
Dans ce cas, les flux sont plus performants. Je me demande ce que l'on observerait dans une application où la fonction de filtrage n'est appelée qu'une ou deux fois pendant l'exécution.
toList
devrait s'exécuter en parallèle même s'il est collecté dans une liste non thread-safe, car les différents threads seront collectés dans des listes intermédiaires confinées aux threads avant d'être fusionnés.
IntStream
place?