2017-10-17 202 views
0

我正在讀取專有的二進制數據文件格式。所述格式基本上報頭,數據,size_of_previous_data,報頭,數據,size_of_previous_data,報頭,數據,size_of_previous_data,...頭的 部分包括數據的下一個塊的字節數以及後被立即列出其大小數據。標題爲256字節,數據通常爲〜2MB,size_of_previous_data爲32位int。讀取大文件的小分離塊(C++)

的文件一般都很大〜GB,我經常有幾十,通過他們對我想要的數據進行搜索。爲了做到這一點,我在代碼中做的第一件事是每個文件都是idex,即只讀入頭文件並記錄相關數據的位置(文件和字節數)。我的代碼基本上使用fstream :: read()準備好頭文件,檢查數據大小,使用fstream :: seekg()跳過數據,然後讀入size_of_previous_data,然後重複,直到到達文件末尾。

我的問題是,這個索引是痛苦的緩慢。數據在我的Windows 10筆記本電腦上的內部7200 rpm硬盤驅動器上,任務管理器顯示我的硬盤驅動器使用率已達到最大,但我的讀取速度僅爲1.5 MB/s,響應時間通常> 70 ms。我正在使用fstream :: get()讀取文件,使用std :: fstream讀取頭文件並將fstream :: seekg()移至下一個頭文件。

我已經異型我的代碼,並幾乎全部時間都花在了的fstream ::閱讀()的代碼讀取size_of_previous_data值。我認爲當我這樣做時,數據立即被緩衝,所以我的fstream :: read()獲得下一個頭幾乎沒有時間。

所以我想知道如果有一種方法來優化呢?幾乎在任何緩衝讀取中,我的整個緩衝區都可能被浪費(如果它是8kB緩衝區,則其中的97%會被浪費)。有沒有辦法縮小這個值,是否值得這麼做(也許底層操作系統緩衝區也是我無法改變的)?

+0

爲什麼不讀一開始的所有文件? RAM的GB通常很好,但搜索GB大小的文件很慢並不令人驚訝 – user463035818

+0

如果數據的大小已經存儲在頭中,那麼爲什麼不在搜索數據時跳過'size_of_previous_data' ?您可以保存讀數,直到您需要讀取數據本身,然後將其用作一種校驗和。如果您一次只讀取256個字節,則不需要比此更大的緩衝區。 –

+1

如果您的操作系統支持它,請嘗試使用內存映射文件。操作系統將爲您處理將塊讀入內存。 –

回答

1

假設磁盤查找大約需要10 ms(來自Latency Numbers Every Programmer Should Know),則您的文件爲11 GB,由2 MB塊組成,理論最小運行時間爲5500 * 10 ms = 55秒。

如果您在幅度上的順序是已經,加快這件事的最有效的方式可能是購買一個SSD。

+0

*假設磁盤查找需要大約10毫秒*這實際上非常樂觀。 7,200 RPM SATA磁盤通常在15 ms範圍內,而5,400 RPM磁盤可以超過20 ms。但我想知道磁盤的帶寬。 70毫秒內的2 MB僅爲28 MB /秒。即使假設70 ms中的20 ms是尋道時間,這意味着磁盤只能移動40 MB /秒。這很低,並且數據路徑上可能還存在其他硬件瓶頸,這意味着SSD無濟於事。 –

+0

如果我正確理解了這個問題,只需要讀取256個字節來構建索引,而不是完整的2 MB。那麼尋求時間成爲瓶頸,而不是帶寬。 – Thomas