2015-06-24 59 views
5

我正在測試一些Java8流的API代碼,但我無法弄清楚這是怎麼回事。Java8流奇怪的行爲

我在想關於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 ms13000 ms)?

+1

嘗試以其他順序調用方法。首先'sequenceSum()'然後'sumWithParallelStream()'。 – Kayaman

+0

你做了兩件完全不同的事情。當你使用並行方法時,你可以在整個列表上進行額外的迭代。當然,這需要更長的時間。 – Nitram

+4

@Nitram我相信他在問爲什麼其他方法會影響'sequenceSum()'的運行時間。我會說「可能是JIT」。 – Kayaman

回答

0

正如@apangin的評論指出的那樣,問題在於GC。

我使用了-XX:+ PrintGCDetails參數來打印GC的執行時間,並且它們是最差的,可能是因爲Streams API的initalization被分配了更多的內存。

3

在第一個示例中,您將分配一個32,768,000個元素的數組,然後通過它進行流式處理。數組分配和內存提取不是必需的,可能是減慢了方法的速度。

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

哇......不敢相信我一直在java 8編碼一段時間,完全錯過了這個功能,謝謝。 – dolan

+0

對不起,這裏的答案是關於評論,我會寫一個答案。 –