Java 8 初探 - Parallel Array Sort

更新於 發佈於 閱讀時間約 5 分鐘
此為過去的舊文,2014 年 5 月 18 日初次發表於 logdown。

最近比較懶一點,所以今天還是只看一個小東西。比較 Arrays 這個工具類別在 J2SE 7J2SE 8 的API文件,會發現 Arrays 多了幾組靜態函式:

  • stream(T[])
  • setAll(T[], IntFunction<T>)
  • parallelSetAll(T[], IntFunction<T>)
  • parallelPrefix(T[], BinaryOperator<T>)
  • spliterator(T[] array)
  • parallelSort(T[], Comparator<T>)

stream(T[])Java 8 初探 - Stream已經介紹過了,這裡只是把一個陣列包裝成 stream 來使用。

setAll(T[], IntFunction<T>)parallelSetAll(T[], IntFunction<T>)的功能是一樣的:用 IntFunction 的回傳值填滿整個 array,IntFunction 接受一個整數作為參數 (即 array 的索引值)。這類函式在產生特定數列時挺好用的,例如用來產生等差數列或等比數列。兩個函式只差在後者是以平行處理的方式填滿 array,速度較快 (也較耗資源)。


parallelPrefix(T[], BinaryOperator<T>) 可用目前索引的前一個數值 (binary operator 的 left 值) 和目前索引所指的值 (binary operator 的 right 值) 計算出新的數值 (有趣的是,Arrays 沒提供非 parallel 的版本),回傳值會填入原陣列中,所以binary operator 的 left 值都會是變更後的值。官方的例子假設元數列式 [2, 1, 0, 3],然後 BinaryOperator<T> 做加法運算,則運算後的數列是 [2, 3, 3, 6]6是根據陣列的第三個數 (left值) 加上第四個數 (right值) 取代原有的第四個數。

spliterator(T[] array) 是用來切割陣列,我猜當呼叫 parallelSort(T[], Comparator<T>) 或是用 stream(T[] array) 取得stream物件後,再次呼叫 parallel() 時,內部會用 spliterator(T[]) 取得 Spliterator 物件管理陣列的切割,用來做平行處理。

Arrays 的其他函式都介紹完了,該看今天的重點:parallelSort(T[], Comparator<T>)。在很早之前 Arrays 就有提供排序的函式,內部用的是 merge sort 演算法,使用時只需要提供比較任意兩物件順序的 Comparator 即可,這次新增的 parallelSort(T[], Comparator<T>) 就是平行處理的版本,所以我比較想知道平行處理版本所帶來的效能增益有多少?

這裡先宣告一個 SortStrategy<T> 的介面,然後分別提供使用非平行處理的SimpleSortStrategy 實作和使用平行處理的 ParallelSortStrategy 實作。接著提供一個函式 generateRandomValues(int) 產生指定數量的亂數數列。


事前準備完後就可以測試有沒有平行處理的差異了,下面的程式可以透過參數決定陣列的最小數量,以及測試要跑幾次,每次都會將陣列的數量加倍,藉此觀察加速是否和數量有關,例如數量越多加速越多?由於比較的次數和交換的次數都會影響到時間,所以先用 generateRandomValues(int) 產生一個亂數list,每種 strategy 執行前才轉為陣列 (轉換不列入時間計算),確保每個 strategy 都是用到相同亂數順序的陣列。測試的環境和先前測試 Java 8 初探 - Lazy Evaluation & Parallel Stream 相似,唯一的不同點是 JVM 從 1.8.0-b132 升級到 1.8.0_05-b13。


結果列於 Table 1,測試的陣列大小從一百萬個整數起跳,跑了 7 個測試到 64 百萬個數字,但跑第七個測試 (64 百萬個數字) 時會拋出 OutOfMemoryError 而失敗,因此只列到排序 32 百萬個數字的六筆比較數據。


Table 1 - The experiment result

Table 1 - The experiment result


從 Table 1 很明顯可以看到 parallelSort(T[], Comparator<T> 大概可以帶來 2.5 倍到接近 3 倍的效能增益 (和數量無關)。所以,結論是當需要處理大量資料的排序時,真的可以考慮使用 parallelSort(T[], Comparator<T>

avatar-img
53會員
104內容數
這是從 Medium 開始的一個專題,主要是想用輕鬆閒談的方式,分享這幾年軟體開發的心得,原本比較侷限於軟體架構,但這幾年的文章不僅限於架構,也聊不少流程相關的心得,所以趁換平台,順勢換成閒談軟體設計。
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
Spirit的沙龍 的其他內容
Java 8 有了 Base64 編解碼器,方便不少,不過 Apache Commons Codec 提供更多常用的編解碼器,其實是更方便的,但如果你的應用程式中只需要 Base64 編解碼器,在有 Java 8 的環境中確實不需要將 Apache Commons Codec 和專案一起打包。
default methods 似乎也引起不小的討論,因為 default methods 加上可以實作多個介面,已經有點像 C++ 的多重繼承了,只差在沒辦法繼承成員變數而已,是好是壞就看怎麼使用了。我個人覺得還蠻方便的
Lazy evaluation 的效益必須是在 pipe 的組合上有最佳化過的,若組合的不好反而更糟糕,且在 I/O 上幫助似乎也不大。parallel stream 要能發揮效果必須看資料的來源類型,不過要注意的是 parallel stream 也會使記憶體的使用量增加,使用上也要小心。
老實說,看到 Java Sream API 讓我感到相當親切,這應該跟我研究所多年的研究題目是 visual dataflow language 有關,Java Stream API 把迴圈給內化了,每個 operation 的重點是要做什麼,大大提高了程式的抽象化程度和可讀性。
最後,Java 8 雖然支援 Lambda,但我覺得 Closure 某種程度上還不稱不上是 Java 的第一級居民,我還是比較喜歡寫一些小而易測的 class,而不是使用 Lambda,至於捕捉變數,透過建構子將變數帶入物件也是一種方式。
Java 8 終於在 2014 的 3 月 18 日正式釋出了,不過自從用 Objective C 開發 iOS App後,我已經有好一陣子沒碰 Java,期間曾經有短暫寫一點點,但卻沒有時間去用 beta 版的 Java 8,直到最近才又開始玩一下。
Java 8 有了 Base64 編解碼器,方便不少,不過 Apache Commons Codec 提供更多常用的編解碼器,其實是更方便的,但如果你的應用程式中只需要 Base64 編解碼器,在有 Java 8 的環境中確實不需要將 Apache Commons Codec 和專案一起打包。
default methods 似乎也引起不小的討論,因為 default methods 加上可以實作多個介面,已經有點像 C++ 的多重繼承了,只差在沒辦法繼承成員變數而已,是好是壞就看怎麼使用了。我個人覺得還蠻方便的
Lazy evaluation 的效益必須是在 pipe 的組合上有最佳化過的,若組合的不好反而更糟糕,且在 I/O 上幫助似乎也不大。parallel stream 要能發揮效果必須看資料的來源類型,不過要注意的是 parallel stream 也會使記憶體的使用量增加,使用上也要小心。
老實說,看到 Java Sream API 讓我感到相當親切,這應該跟我研究所多年的研究題目是 visual dataflow language 有關,Java Stream API 把迴圈給內化了,每個 operation 的重點是要做什麼,大大提高了程式的抽象化程度和可讀性。
最後,Java 8 雖然支援 Lambda,但我覺得 Closure 某種程度上還不稱不上是 Java 的第一級居民,我還是比較喜歡寫一些小而易測的 class,而不是使用 Lambda,至於捕捉變數,透過建構子將變數帶入物件也是一種方式。
Java 8 終於在 2014 的 3 月 18 日正式釋出了,不過自從用 Objective C 開發 iOS App後,我已經有好一陣子沒碰 Java,期間曾經有短暫寫一點點,但卻沒有時間去用 beta 版的 Java 8,直到最近才又開始玩一下。
你可能也想看
Google News 追蹤
Thumbnail
大家好,我是woody,是一名料理創作者,非常努力地在嘗試將複雜的料理簡單化,讓大家也可以體驗到料理的樂趣而我也非常享受料理的過程,今天想跟大家聊聊,除了料理本身,料理創作背後的成本。
Thumbnail
哈囉~很久沒跟各位自我介紹一下了~ 大家好~我是爺恩 我是一名圖文插畫家,有追蹤我一段時間的應該有發現爺恩這個品牌經營了好像.....快五年了(汗)時間過得真快!隨著時間過去,創作這件事好像變得更忙碌了,也很開心跟很多厲害的創作者以及廠商互相合作幫忙,還有最重要的是大家的支持與陪伴🥹。  
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
題目敘述 Make Two Arrays Equal by Reversing Subarrays 題目給定兩個輸入陣列,請問能否透過子陣列的反轉讓兩個陣列相等? 子陣列的反轉操作次數不受限制。 如果可以,返回True 如果不行,返回False
Thumbnail
題目敘述 Sort Array by Increasing Frequency Leetcode #1636 給定一個輸入陣列,請依照出現頻率的多寡從低頻到高頻排列陣列元素。 如果有兩個元素的出現頻率相同,依照元素大小從大到小排列。 測試範例 Example 1: Input: nums
Thumbnail
本章節的目的是介紹Java中的運算符,包括算數運算符、比較運算符、賦值運算符、位元運算符以及運算符的優先等級。通過本章節,讀者可以了解到如何在Java中進行基本的數學運算、比較兩個值的大小、將值賦給變數、進行位元運算,以及在複雜表達式中如何正確地理解運算符的優先等級。
Thumbnail
題目敘述 Sort Colors 給定一個色彩陣列,裡面的顏色包含0紅色,1白色,2藍色。 要求我們透過in-place操作,把色彩陣列依序從左到右排好, 依序出現的是紅色、白色、藍色。
Thumbnail
給定一個輸入非負整樹陣列nums,請找出k值,使得陣列中恰好有k個元素大於等於 k。如果無解,回傳-1。尋找k值的方法包括排序法和二分搜尋法,時間複雜度都為O(n log n),空間複雜度為O(1)。關鍵知識點是當解空間具有遞增或遞減的性質時,可以用二分搜尋法加快搜尋效率。
※ 好用的陣列迭代器:forEach forEach 的使用時機: 需要從頭到尾把陣列中的每一個元素都印出來 ,就適合使用 forEach 方法。 forEach 的必要參數是一個函式: forEach() 的功能是把陣列的每個元素都丟進某個函式執行一次,因此必要的參數是一個函式。 語法:
※ 常用arry型態的方法: 長度: length 查詢第N個元素: [] 查詢元素在第N個: indexOf( ) 判斷是否為array: isArray() 新增和刪除: push():新增後面的數值 unshift():新增前面的數值 pop():刪除後面的數值 sh
Thumbnail
題目敘述 題目會給定我們兩個整數陣列作為輸入nums1, nums2,要求我們找出兩個陣列的差異值。 找出在nums1但是不在nums2的元素,以陣列的形式放在answer[0]輸出。 找出在nums2但是不在nums1的元素,以陣列的形式放在answer[1]輸出。 題目的原文敘述
描述順序的方式有很多種,可以用數字標示文字的方式,如下 文字 文字 文字 用數字標示文字的方式我覺得有個特質是,文字重要的程度是遞減的,也就是數字從一往後會越來越不重要。這個現象是我在寫這篇文的當下感覺到的,可能是我在過去經驗聽過有人說越重要的東西要先擺在前面;又或者是我在高中以前的
Thumbnail
大家好,我是woody,是一名料理創作者,非常努力地在嘗試將複雜的料理簡單化,讓大家也可以體驗到料理的樂趣而我也非常享受料理的過程,今天想跟大家聊聊,除了料理本身,料理創作背後的成本。
Thumbnail
哈囉~很久沒跟各位自我介紹一下了~ 大家好~我是爺恩 我是一名圖文插畫家,有追蹤我一段時間的應該有發現爺恩這個品牌經營了好像.....快五年了(汗)時間過得真快!隨著時間過去,創作這件事好像變得更忙碌了,也很開心跟很多厲害的創作者以及廠商互相合作幫忙,還有最重要的是大家的支持與陪伴🥹。  
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
題目敘述 Make Two Arrays Equal by Reversing Subarrays 題目給定兩個輸入陣列,請問能否透過子陣列的反轉讓兩個陣列相等? 子陣列的反轉操作次數不受限制。 如果可以,返回True 如果不行,返回False
Thumbnail
題目敘述 Sort Array by Increasing Frequency Leetcode #1636 給定一個輸入陣列,請依照出現頻率的多寡從低頻到高頻排列陣列元素。 如果有兩個元素的出現頻率相同,依照元素大小從大到小排列。 測試範例 Example 1: Input: nums
Thumbnail
本章節的目的是介紹Java中的運算符,包括算數運算符、比較運算符、賦值運算符、位元運算符以及運算符的優先等級。通過本章節,讀者可以了解到如何在Java中進行基本的數學運算、比較兩個值的大小、將值賦給變數、進行位元運算,以及在複雜表達式中如何正確地理解運算符的優先等級。
Thumbnail
題目敘述 Sort Colors 給定一個色彩陣列,裡面的顏色包含0紅色,1白色,2藍色。 要求我們透過in-place操作,把色彩陣列依序從左到右排好, 依序出現的是紅色、白色、藍色。
Thumbnail
給定一個輸入非負整樹陣列nums,請找出k值,使得陣列中恰好有k個元素大於等於 k。如果無解,回傳-1。尋找k值的方法包括排序法和二分搜尋法,時間複雜度都為O(n log n),空間複雜度為O(1)。關鍵知識點是當解空間具有遞增或遞減的性質時,可以用二分搜尋法加快搜尋效率。
※ 好用的陣列迭代器:forEach forEach 的使用時機: 需要從頭到尾把陣列中的每一個元素都印出來 ,就適合使用 forEach 方法。 forEach 的必要參數是一個函式: forEach() 的功能是把陣列的每個元素都丟進某個函式執行一次,因此必要的參數是一個函式。 語法:
※ 常用arry型態的方法: 長度: length 查詢第N個元素: [] 查詢元素在第N個: indexOf( ) 判斷是否為array: isArray() 新增和刪除: push():新增後面的數值 unshift():新增前面的數值 pop():刪除後面的數值 sh
Thumbnail
題目敘述 題目會給定我們兩個整數陣列作為輸入nums1, nums2,要求我們找出兩個陣列的差異值。 找出在nums1但是不在nums2的元素,以陣列的形式放在answer[0]輸出。 找出在nums2但是不在nums1的元素,以陣列的形式放在answer[1]輸出。 題目的原文敘述
描述順序的方式有很多種,可以用數字標示文字的方式,如下 文字 文字 文字 用數字標示文字的方式我覺得有個特質是,文字重要的程度是遞減的,也就是數字從一往後會越來越不重要。這個現象是我在寫這篇文的當下感覺到的,可能是我在過去經驗聽過有人說越重要的東西要先擺在前面;又或者是我在高中以前的