Java 8は初めてです。APIの詳細はまだわかりませんが、新しい非公式のベンチマークを作成して、新しいStreams APIと古き良きコレクションのパフォーマンスを比較しました。
このテストでは、のリストをフィルタリングし、Integer
偶数ごとに平方根を計算しての結果List
に格納しDouble
ます。
これがコードです:
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));
}.
そして、これがデュアルコアマシンの結果です:
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)
この特定のテストでは、ストリームの速度はコレクションの約2倍であり、並列処理は役に立ちません(または、間違った方法で使用していますか?)。
質問:
- このテストは公正ですか?間違えましたか?
- ストリームはコレクションよりも遅いですか?誰かがこれについて正式なベンチマークを作成しましたか?
- どちらのアプローチをとるべきですか?
結果を更新しました。
@pveentjerの助言に従って、JVMウォームアップ(1k回の反復)の後にテストを1,000回実行しました。
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)
この場合、ストリームのパフォーマンスが向上します。フィルタリング関数が実行時に1回または2回だけ呼び出されるアプリで何が観察されるのでしょうか。
toList
は、異なるスレッドがマージされる前にスレッド限定の中間リストに収集されるため、非スレッドセーフリストに収集している場合でも、並列で実行する必要があります。
IntStream
代わりに試してみましたか?