第41期:文件的性能分析
我們以前講過硬盤的性能特征,主要是針對硬件層面進行分析的,現在我們來考慮軟件層面的差異。
理論上講,軟件可以穿過操作系統直接進行磁盤扇區的訪問,但實在太過于麻煩而幾乎不會實踐機會,這里就不考慮了,我們只討論操作系統下的存儲形式,而文件就是其中重要的存儲形式。
文件一般有兩種:文本文件和二進制文件,我們分別來討論。
文本文件
文本是很常見的數據存儲形式,它具有通用性易讀性等優點而被廣泛使用。但是,文本的性能卻非常差!
文本字符不能直接運算,需要轉換成整數、實數、日期、字符串等內存數據類型才可以進一步處理,而文本的解析是個非常復雜的任務。
舉個例子,設想一下把文本“12345"轉成內存二進制整數12345的過程:
- 先設結果的初始值為0
- 拆出字符“1”,解析出數值1,將初值0乘以10加上這個1得到數值1
- 再拆出字符“2”,解析出數值2,把剛才的1乘以10和這個2相加得到數值12
- 再拆出字符“3”,解析出數值3,把剛才的12再乘以10加上這個3得到數值123
- ...
有些C程序員知道用函數atoi()可以實現字串到整數的轉換,僅僅一句代碼,看似非常簡單,但其實背后的步驟非常多,CPU要干很多事才能完成這個動作,耗時并不短。實際過程中還要判斷可能出現的非法字符(比如不是數字的字符),比上面描述的步驟還要更復雜得多。
整數還是最簡單的數據類型,如果是實數還要處理小數點,字符串解析時要考慮轉義字符和引號匹配,日期的解析更是要麻煩得多,因為格式種類太多,2018/1/10和10-1-2018都是常見的合法日期格式,甚至還有Jan-10 2018這種,要正確解析,就得嘗試用多種格式去匹配,CPU耗時很嚴重。
一般來講,外存數據訪問的主要時間是在硬盤本身的讀取上,而文本文本的性能瓶頸卻經常發生在CPU環節。因為解析的復雜性,CPU耗時很可能超過硬盤耗時(特別是采用高性能固態硬盤時)。文本是非常慢的,需要高性能處理大數據時不要使用文本!
但是,有些原始數據(如日志)只有文本形式,解析文本就是不可避免的任務。這時候,一方面可以采用并行技術,利用多CPU并行度更高的特性,由多個線程同時解析文本,這樣即使仍然串行訪問硬盤也能獲得更高的文本處理性能;另一方面,這些數據如果需要反復使用,那么***是轉換成二進制格式存儲,第二次使用不要再次解析。
二進制文件
二進制文件中,我們會將各種數據類型對應的內存字節直接寫出到文件中,再讀取時也只要直接取出重新裝載成內存數據,沒有復雜的解析過程,也不需要判斷和識別非法情況,這時性能就會好很多。
不過,用二進制數據存儲時需要考慮好壓縮手段,否則在某些極端情況下會比文本的存儲空間更大,雖然解析時間縮短,但硬盤訪問時間會變長。
比如整數1,用文本存儲時只要占一個字節,即使加上分隔符也就兩個字節。而如果要把所有整數都按32位整數處理(當前計算機的整數數據類型大多數是這個位長),就需要用4個字節來存儲,比文本大了一倍,有時可能還要加上數據類型本身的信息,就會更長。
對于這種情況,合理的做法是根據數的大小決定位長,比如小整數只存儲一個字節或兩個字節,大整數才存儲更多的字節,因為小整數較常見,結果會使得總體存儲空間降低,從而獲得性能優勢。
但是,壓縮率并不是越高越好,解壓縮需要消耗CPU時間。象上面說的,把整數分大小存儲能夠減少空間,但在解析時就要多一重判斷,又降低一點性能。***采用的壓縮方案,要在硬盤空間的減少和CPU的消耗中取得某種平衡。如果一味地追求壓縮率(比如使用zip壓縮算法),空間是降低得更多,但CPU時間將會超過硬盤時間,整體性能反而下降。
不過,無論如何,二進制文件仍然是最快的存儲格式。采用簡單壓縮方案的二進制文件,即使同樣采用行式存儲,一般也能達到比文本高4-5倍的性能。使用二進制格式,還有可能使用前面文章中提到過的分段并行技術和列存技術,從而獲得更高的性能。