2015-06-24 5 views
5

Я тестировал некоторые коды API-интерфейсов Java8, но я не могу понять, что происходит с этим.Java8 streams странное поведение

Я думал о ParallelStream и о том, как это работает, и я сделал некоторые сравнения. Два разных метода, которые выполняют большую итерацию, добавляя 32.768.000 BigDecimals, используя ParallelStream, другие используют обычную итерацию. Я пришел с тестом, что знаю, что он недействителен, но некоторые вещи вызвали мое внимание.

Тесты:

Параллельный поток:

private static void sumWithParallelStream() { 
    BigDecimal[] list = new BigDecimal[32_768_000]; 
    BigDecimal total = BigDecimal.ZERO; 
    for (int i = 0; i < 32_768_000; i++) { 
     list[i] = new BigDecimal(i); 
    } 
    total = Arrays.asList(list).parallelStream().reduce(BigDecimal.ZERO, BigDecimal::add); 
    System.out.println("Total: " + total); 
} 

Нормальный код:

private static void sequenceSum() { 
    BigDecimal total = BigDecimal.ZERO; 
    for (int i = 0; i < 32_768_000; i++) { 
     total = total.add(new BigDecimal(i)); 
    } 
    System.out.println("Total: " + total); 
} 

Выход:

Total: 536870895616000 
sumWithParallelStream(): 30502 ms 

Total: 536870895616000 
sequenceSum(): 271 ms 

Затем я попытался удалить parallelStream:

private static void sumWithParallelStream() { 
    BigDecimal[] list = new BigDecimal[32_768_000]; 
    BigDecimal total = BigDecimal.ZERO; 
    for (int i = 0; i < 32_768_000; i++) { 
     list[i] = new BigDecimal(i); 
     total = total.add(list[i]); 
    } 
    System.out.println("Total: " + total); 
} 

видеть, что метод sequenceSum() является тем же

Новый выход:

Total: 536870895616000 
sumWithParallelStream(): 13487 ms 

Total: 536870895616000 
sequenceSum(): 879 ms 

Я сделал эти изменения, добавления и удаления parallelStream метода множество раз и результаты sequenceSum() никогда не меняются, всегда что-то около 200 при использовании parallelStream по другому методу, и что-то около 800 когда не используется. Тестирование в Windows и Ubuntu.

И, наконец, осталось два вопроса, почему использование parallelStream на первом методе влияет на второй? Почему сохранение BigDecimals на массиве сделало первый метод слишком медленным (800 ms - 13000 ms)?

+1

Попробуйте вызвать методы в другом порядке. Сначала 'sequenceSum()', а затем 'sumWithParallelStream()'. – Kayaman

+0

Вы делаете две очень разные вещи. Когда вы используете параллельный метод, у вас есть дополнительная итерация по всему списку. Конечно, это занимает больше времени. – Nitram

+4

@Nitram Я считаю, что он спрашивал, почему другой метод влияет на время выполнения 'sequenceSum()'. Для чего я бы сказал «JIT» наверное. – Kayaman

ответ

0

Как указано в комментариях @apangin, проблема связана с GC.

Я использовал -XX: + PrintGCDПодробный параметр для печати времени выполнения GC и с parallelStream они были худшими, может быть, потому, что была выделена инициализация интерфейса Streams API.

3

В первом примере вы выделяете массив из 32 768 000 элементов, а затем передают его по потоку. Это распределение массивов и выборка памяти не нужны и, вероятно, это то, что замедляет метод.

IntStream.range(0, limit).parallel() 
    .mapToObj(BigDecimal::new) 
    .reduce(BigDecimal.ZERO, BigDecimal::add); 
+0

wow ... Не могу поверить, что я кодировал в java 8 некоторое время и полностью пропустил эту функцию, спасибо. – dolan

+0

Извините, ответ здесь на комментарии, я напишу ответ. –

Смежные вопросы