Java8影響並行流效能的主要因素

2021-08-21 03:45:08 字數 1908 閱讀 4101

影響並行流效能的主要因素有5 個,依次分析如下。

輸入資料的大小會影響並行化處理對效能的提公升。將問題分解之後並行化處理,再將結果合併會帶來額外的開銷。因此只有資料足夠大、每個資料處理管道花費的時間足夠多時,並行化處理才有意義。

每個管道的操作都基於一些初始資料來源,通常是集合。將不同的資料來源分割相對容易,這裡的開銷影響了在管道中並行處理資料時到底能帶來多少效能上的提公升。

處理基本型別比處理裝箱型別要快。

極端情況下,只有乙個核,因此完全沒必要並行化。顯然,擁有的核越多,獲得潛在效能提公升的幅度就越大。在實踐中,核的數量不單指你的機器上有多少核,更是指執行時你的機器能使用多少核。這也就是說同時執行的其他程序,或者執行緒關聯性(強制執行緒在某些核或cpu 上執行)會影響效能。

比如資料大小,這是一場並行執行花費時間和分解合併操作開銷之間的戰爭。花在流中每個元素身上的時間越長,並行操作帶來的效能提公升越明顯。

使用並行流框架,理解如何分解和合併問題是很有幫助的。這讓我們能夠知悉底層如何工作,但卻不必了解框架的細節。

來看乙個具體的問題,看看如何分解和合併它。如下是很簡單的並行求和的**。

private static int addintegers(listvalues)
在底層,並行流還是沿用了fork/join 框架。fork 遞迴式地分解問題,然後每段並行執行,最終由join 合併結果,返回最後的值。

下圖形象地展示了上面**所示的操作。

使用fork/join 分解合併問題

假設並行流將我們的工作分解開,在乙個四核的機器上並行執行。

1. 資料被分成四塊。

2. 如**所示,計算工作在每個執行緒裡並行執行。這包括將每個integer 物件對映為int值,然後在每個執行緒裡將1/4 的數字相加。理想情況下,我們希望在這裡花的時間越多越好,因為這裡是並行操作的最佳場所。

3. 然後合併結果。在上面**中,就是sum 操作,但這也可能是reduce、collect 或其他終結操作。

根據問題的分解方式,初始的資料來源的特性變得尤其重要,它影響了分解的效能。直觀上看,能重複將資料結構對半分解的難易程度,決定了分解操作的快慢。能對半分解同時意味著待分解的值能夠被等量地分解。

我們可以根據效能的好壞,將核心類庫提供的通用資料結構分成以下3 組。

arraylist、陣列或intstream.range,這些資料結構支援隨機讀取,也就是說它們能輕而易舉地被任意分解。

hashset、treeset,這些資料結構不易公平地被分解,但是大多數時候分解是可能的。

有些資料結構難於分解,比如,可能要花o(n) 的時間複雜度來分解問題。其中包括linkedlist,對半分解太難了。還有streams.iterate 和bufferedreader.lines,它們長度未知,因此很難**該在**分解。

初始的資料結構影響巨大。舉乙個極端的例子,對比對10 000 個整數並行求和,使用arraylist要比使用linkedlist 快10 倍。這不是說業務邏輯的效能情況也會如此,只是說明了資料結構對於效能的影響之大。使用形如linkedlist 這樣難於分解的資料結構並行執行可能更慢。

理想情況下,一旦流框架將問題分解成小塊,就可以在每個執行緒裡單獨處理每一小塊,執行緒之間不再需要進一步通訊。無奈現實不總遂人願!

在討論流中單獨操作每一塊的種類時,可以分成兩種不同的操作:無狀態的和有狀態的。無狀態操作整個過程中不必維護狀態,有狀態操作則有維護狀態所需的開銷和限制。

如果能避開有狀態,選用無狀態操作,就能獲得更好的並行效能。無狀態操作包括map、filter 和flatmap,有狀態操作包括sorted、distinct 和limit。

Java 8 並行流 序列流

2 容器操作 3 容器 rootfs 命令 4 映象倉庫 5 本地顯像管理 6 info version 當docker run建立容器時,docker的標準操作包括 利用映象建立並啟動乙個容器 分配乙個檔案系統,並在唯讀的映象層外面掛載一層可讀寫層 從宿主主機配置的網橋介面中橋接乙個虛擬介面到容器...

JAVA 8 併發增強 6 並行陣列

string contents new string files.readallbytes paths.get test.txt standardcharsets.utf 8 string words contents.split p 根據非字母字元對字串進行分隔 arrays.parallelso...

Java8之Stream流代替For迴圈

stream流代替for迴圈進行輸出可以使 更簡潔。需求 根據姓名獲取員工資訊 1.建立實體類 emp public class emp public string getid public void setid string id public string getname public void...