現代計算機一般都有多 cpu 核,而日益廣泛應用的固態硬碟也有較強的併發能力,這些硬體資源都為平行計算提供了有力的保證。不過,要實現平行計算還需要有較好的資料分段技術,也就是能方便地把待計算的資料拆分成若干部分,讓每個執行緒(或程序,這裡以多執行緒為例討論,多程序情況是類似的)分別處理。
設計資料分段方案時,有這麼幾個目標:
並行任務的最終耗時是以那個最慢的執行緒為準的,而同一機器中各執行緒的處理能力基本相當,因此資料分段要能做到盡量平均,使各執行緒的計算時間基本相同。
在資料準備階段經常並不清楚實際計算用機器的 cpu 數,而且即使知道,執行緒數也不能簡單地按機器 cpu 核數去算,因為硬碟的併發能力常常小於 cpu;並且,在有併發計算時,能有多少 cpu 核用到本計算任務也不能事先預知。實際計算用的執行緒數最好是根據當時場景動態決定,範圍從幾個到幾十個都有可能,這要求能夠按隨意的數量將資料分段。
因為硬碟不適合頻繁隨機訪問(即使固態硬碟也不適合頻繁小量的隨機訪問),為了保證遍歷性能,我們希望每個執行緒要處理的資料在硬碟上要盡量連續儲存,而不是頻繁跳躍。
資料並不是固定不變的,會隨著時間不斷增長,我們當然希望每次追加資料時不必重新整理所有資料,只需要把追加的資料補上即可。
使用文字檔案儲存資料時,可以同時保證這 4 個目標。只要簡單地按總位元組數把檔案分成多段,每個執行緒讀取其中一段即可。
文字中用回車作為記錄(行)的分隔符,文字記錄的資料本身中不可能出現回車字元,所以用它用為記錄的分隔符不會產生歧義。按檔案位元組數分段時,分段點可能會落到某一行的中間,這時使用去頭補尾的方法進行調整,即就是每個分段從分段點繼續讀到乙個回車符才開始,而越過下乙個分段點繼續讀到乙個回車符時才結束,這樣就可以保證每個分段都只包含完整的記錄(行),這也是 hadoop 常用的方法。
但是,文字本身的解析實在太慢了,我們還是要考慮二進位制的儲存方案。
二進位制資料中沒有回車這種可用於分隔記錄的字元,任何位元組數值都可能是資料本身,這時就無法識別出記錄何時結束。如果一定要人為製造乙個分隔符,那就要足夠長才能避免和資料本身重複的可能性,每條記錄上都增加這麼一段位元組,會增加大量無意義的資料量,降低效能。而且,這也只能降低出錯率而不能徹底杜絕。
改進的方法是使用區塊,把資料存入若干相同大小的區塊,分段時以區塊為單位,只要總區塊數量足夠多,每個執行緒分配到的區塊數量也就相對比較平均,也就能滿足目標 1 和目標 2 了。不過目標 3 卻有些問題,區塊大小是儲存資料之前就確定的,不大可能正好和記錄長度匹配,如果要求每個區塊中都儲存完整的記錄,就可能造成區塊中的空間浪費(剩餘空間存不下一條完整記錄時只能作廢)。在區塊較小且記錄欄位較多時這個浪費會很嚴重,影響目標 3 希望的緊湊性。如果允許一條記錄被拆分到兩個區塊,那又不能按區塊為單位來分段了,否則可能造成某個分段將只處理半條記錄的情況。
這時候可以借鑑文字的去頭補尾方案,允許同一記錄拆分到兩個區塊,在讀取分段的第乙個區塊時跳過第一條(可能是半條)記錄,而讀取最後乙個區塊時再繼續讀下乙個區塊把當前區塊中最後的記錄讀完整,這樣可以保證資料的緊湊性了。這種方法要求在區塊中有個標記表明本區塊中第一條記錄是否是上一區塊記錄的延續以及最後一條記錄是否完整,空間成本不算高,但在遍歷資料時總要被這些標記打斷,處理起來麻煩不少,會影響效能。
資料庫一般也使用區塊方案,但由於資料庫將所有表的資料儲存在一起,它的區塊分配演算法不會去保證同表資料所占用的區塊之間的連續性。而為提高資料的連續性,就要讓區塊更大,這和區塊多又有點矛盾。如果再考慮到資料的可追加性,則還需要乙個不斷變大的索引表來管理這些區塊,在區塊數量很多時,這個索引表本身的連續性也不容易得到保證(它的長度事先不知道,在資料追加過程中動態增長)。
日期資料操作第1期 datetime庫
日期資料操作挺重要的,之前分享過 python中處理日期時間庫的使用方法 arrow日期時間處理庫 現在覺得日期資料的操作挺重要的,準備分割成小知識點,連續更新幾天。今天更新第一期 datetime庫 日期時間類,常用的引數包含year month day hour minute second mi...
第 40 期 倍增分段技術
區塊分段方案能夠滿足我們設定的 4 個目標。不過,除了處理區塊標記的麻煩外,這個辦法對於列存也不是非常適合。資料按列分別儲存後,分段時必須保證各列同步,即各列的分段點對應的是同一條記錄的列,否則就會出錯資料錯位。而各個列的寬度是不同的,同樣大小的區塊在儲存不同列的值時,能裝下的個數是不同的,繼續按區...
Datawhale 第20期 資料視覺化Task1
matplotlib的影象是畫在figure 如windows,jupyter窗體 上的,每乙個figure又包含了乙個或多個axes 乙個可以指定座標系的子區域 最簡單的建立figure以及axes的方式是通過pyplot.subplots命令,建立axes以後,可以使用axes.plot繪製最簡...