Я новачок у Java 8. Я все ще не знаю API поглиблено, але я зробив невеликий неформальний орієнтир, щоб порівняти продуктивність нового API Streams з старими хорошими колекціями.
Тест складається в фільтрації списку 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)
У цьому конкретному тесті потоки приблизно вдвічі повільніше, ніж колекції, і паралелізм не допомагає (або я використовую його неправильно?).
Запитання:
- Чи справедливий цей тест? Чи зробив я якусь помилку?
- Чи потоки повільніше, ніж колекції? Хтось зробив хороший офіційний орієнтир щодо цього?
- До якого підходу слід прагнути?
Оновлені результати.
Я провів тест 1 к разів після розминки JVM (1 к ітерації), як радив @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)
У цьому випадку потоки є більш ефективними. Цікаво, що б спостерігалося в додатку, де функція фільтрації викликається лише один чи два рази під час виконання.
toList
має запускатися паралельно, навіть якщо він збирається до небезпечного списку, оскільки різні потоки збиратимуться до проміжних списків, обмежених потоками, перш ніж об'єднати.
IntStream
замість цього?