天天看點

并行正則采樣排序算法及在 Mars 中的應用

相信大家對排序算法都非常熟悉了,快速排序、堆排序、歸并排序等等。如果我們想在一個很大的資料集上進行排序,能利用上多核,甚至是分布式叢集,有什麼辦法麼?

本文就介紹一種并行排序算法:并行正則采樣排序算法(Parallel Sorting by Regular Sampling),簡稱 PSRS 算法。

PSRS 算法過程

并行正則采樣排序算法及在 Mars 中的應用

PSRS 算法的整個過程分為四步,如圖所示,我們拆解開來講。

現在假設我們有一個數組,有 48 個元素,現在資料被分成4份,即有4個分區。

階段1,每個分區分别排序,并正則采樣

我們對每個分區的資料調用快速排序,這樣每個分區都是排好的資料。接着,我們從排好序的資料裡正則采樣4個資料。所謂正則,即有規律的,這裡我們就每隔4個元素采樣一個元素。

階段2,歸并采樣資料,選出關鍵點

前面四個分區産生了4份采樣資料,收集之,然後調用歸并排序讓他們有序。接着,我們從中選出 p - 1 (p 是分區個數)個關鍵點,這裡還是正則采樣的方式。

階段3,資料分區

此時将關鍵點資料廣播給每個分區,每個分區就可以根據關鍵點,将資料分成4份,使得每個資料落在各自的範圍内。

階段4,合并資料,歸并排序

最後一個階段是一個 shuffle 階段,即每個下遊都依賴前面的所有上遊。此時每個分區将上遊分好的資料收集起來,最終再進行一個歸并排序。這樣,我們最終的結果就是整體排序的了。

整個過程中,階段1、階段3 和 階段4 可以并行。

MPI 的實作可以參考

這裡

PSRS 算法在 Mars 中的應用

Mars

以并行和分布式化 Python 資料科學棧為目标,PSRS 算法能很好解決并行排序問題,是以,Mars 中和排序有關的操作都是基于 PSRS 算法實作的。

以張量排序為例。

首先我們通過 Numpy 建立 1 億個元素的數組。

In [1]: import numpy as np                                                      

In [2]: a = np.random.rand(1_0000_0000)                                         

In [3]: a.nbytes                                                                
Out[3]: 800000000           

我們來看看使用 Numpy 的排序需要多久。

In [4]: %time np.sort(a)                                                        
CPU times: user 10.8 s, sys: 394 ms, total: 11.2 s
Wall time: 9.4 s
Out[4]: 
array([1.05764619e-10, 5.86309734e-09, 1.76225879e-08, ...,
       9.99999976e-01, 9.99999983e-01, 9.99999998e-01])           

接着,我們來看看基于 PSRS 算法的 Mars tensor 排序需要多長時間。

In [10]: t = mt.tensor(a, chunk_size=1500_0000)                                 

In [12]: %time mt.sort(t).execute()                                             
CPU times: user 18.7 s, sys: 7.03 s, total: 25.7 s
Wall time: 2.66 s           

在我的筆記本上,可以看到 Numpy 的排序時長是 Mars 的 3.53 倍。

總結

本文介紹了并行正則排序算法,這個算法也在 Mars 項目裡得到了廣泛的使用。

如果對 Mars 感興趣,可以關注

Mars 團隊專欄

,或者釘釘掃二維碼加入 Mars 讨論群。

并行正則采樣排序算法及在 Mars 中的應用