在進行大規模數據處理時,讀文件很有可能成為速度瓶頸。不管你的CPU有4個核還是8個核,主頻有2G還是3G,硬盤IO速度總是有個上限的。在本人最近的一次經歷中,對一個11G的文本進行數據處理,一共耗時34.8秒,其中竟然有30.2秒用在訪問IO上,占了所有時間的87%左右。
雖然說硬盤IO是有上限的,那麼C++為我們提供的各函數,是否都能讓我們達到這個上限呢?為了求得真相,我對這個11G的文本用fread函數讀取,在linux下用iostat檢查硬盤的訪問速度,發現讀的速度大約在380M/s。然後用dd指令測了一下讀文本的訪問速度,發現速度可以達到460M/s。可見單線程fread訪問並沒有達到硬盤的讀取上限。第一次考慮會不會是fread訪問硬盤的時候有一些固定開銷,用多線程可以達到流水訪問IO的效果提高讀文本的效率,結果發現多線程也只有380M/s的讀取速率。
為什麼fread的效率達不到最大呢?查閱一些資料才知,用fread/fwrite方式訪問硬盤,用戶須向內核指定要讀多少,內核再把得到的內容從內核緩沖池拷向用戶空間;寫也須要有一個大致如此的過程。這樣在訪問IO的時候就多經歷了這麼一個內核的buffer,造成速度的限制。一個解決的辦法是mmap。mmap就是通過把文件的某一塊內容直接映射到用戶空間上,用戶可以直接向內核緩沖池讀寫這一塊內容,這樣一來就少了內核與用戶空間的來回拷貝所以通常更快。
為了從數據說明這個問題,我引用一位網友的結論,希望對大家有所啟發。
方法/平台/時間(秒) Linux gcc Windows mingw Windows VC2008
scanf 2.010 3.704 3.425
cin 6.380 64.003 19.208
cin取消同步 2.050 6.004 19.616
fread 0.290 0.241 0.304
read 0.290 0.398 不支持
mmap 0.250 不支持 不支持
Pascal read 2.160 4.668