2016-12-21 126 views
7

我需要讀取/解析大小爲8192字節的固定塊的二進制文件(4〜6 GB)。我目前的解決方案涉及使用單生產者多用戶(SPMC)模式對文件塊進行流式傳輸。多線程文件讀取

編輯

文件大小= N * 8192個字節

所有我需要做的是做一些事來每個8192個字節。該文件只需要自上而下閱讀一次。

轉念一想,這應該是一個尷尬的並行問題,我想有X線程在同等範圍內讀取(文件大小/ X)獨立尺寸。線程根本不需要互相通信。

我已經試過產卵X線程打開相同的文件,尋求各自的部分來處理,但是,這種解決方案似乎有一個問題,在由於HDD機械力求顯然比執行更糟糕SPMC解決方案。

如果在SSD上使用此方法,會有什麼區別嗎?

或者更簡單的方法是隻對內存映射整個文件並使用#pragma omp parallel for來處理這些塊?我想我會需要足夠的RAM來做到這一點?

你會建議什麼?

+0

您不會對文件的語法和格式有足夠的瞭解。 –

+1

它是一個N * 8192字節的二進制文件,我需要對這8192個字節分別進行操作。 –

+2

系統調用(假設Linux操作系統)提到[這裏](http://stackoverflow.com/a/41237690/841108)可能會有所幫助。但我猜想瓶頸是磁盤本身。你可能不需要太多的線程。 (所以* X *將會是4到10,不會有很多)。你應該基準。這不是一個令人尷尬的並行問題,因爲硬件磁盤一次只能處理一個(或很少)請求。 –

回答

5

你會建議什麼?

不要使用mmap()

Linux Torvalds himself

人們喜歡的mmap()等方式與頁表發揮 優化掉複製操作,有時這是值得的。然而,使用虛擬內存映射玩遊戲非常昂貴。它有一些非常真實的缺點, 人們往往忽視,因爲內存複製被認爲是非常緩慢的東西,有時優化該副本遠離被視爲顯而易見的 改進。

不利之處MMAP:

  • 相當明顯的安裝和拆卸的成本。我的意思是明顯的。 就像在頁表中清除所有內容一樣。這是記錄所有
    映射的列表。這是取消映射東西后需要的TLB刷新。
  • 頁面錯誤是昂貴的。這就是地圖填充的方式,而且速度很慢。 MMAP的

上升空間:

  • 如果數據被重新使用一遍又一遍(在一張地圖操作中),或者如果你可以通過只在映射的東西避免了很多其他的邏輯,mmap()只是自切片面包以來最偉大的事情。

這可能是你很多次去了一個文件(可執行的二進制圖像是明顯的情況下,在這裏 - 代碼跳轉各地的地方),或設置在那裏,實在太方便映射而不考慮mmap()剛剛贏得的實際使用模式。您可能有隨機訪問模式,並使用mmap()作爲跟蹤您實際需要的數據的一種方式。

  • 如果數據很大,mmap()是讓系統知道它可以對數據集做些什麼的好方法。內存可能因爲內存壓力而忘記頁面,迫使系統將頁面內容分頁,然後再自動重新獲取它們。

    而自動共享顯然就是這樣的一個例子。

但你的測試套件(只複製一次數據)可能是pessimal 對mmap()的。

注意最後 - 只使用一次數據對於mmap()是一個不好的用例。

有關的SSD文件,因爲沒有物理磁頭尋道動作:

  1. 打開文件一次,使用open()得到一個int文件描述符。

  2. 每個線程使用pread()來讀取適當的8kB塊。 pread()不使用lseek()而從指定的偏移量讀取,並且不會影響正在讀取的文件的當前偏移量。

由於在每個線程中都會有相當多的IO等待,因此您可能需要比CPU核心更多的線程。

對於機械硬盤(一個或多個)上的一個文件:

你希望儘量減少磁頭尋道(S)機械磁盤上​​。

打開文件一次,使用open()直接IO(假設Linux的,open(filename, O_RDONLY | O_DIRECT);)繞過頁面緩存(因爲你要流的文件,從來沒有重讀的任何部分,頁面緩存做了你這裏沒有好)

  1. 使用單個生產者線程,讀取大塊(說64K到1MB +) 爲N頁對齊緩衝器中的一個。
  2. 當讀取一個緩衝區,將其傳遞給工作線程,然後讀,填補了一個緩衝

  3. 當所有的工人正在用自己的緩衝區的部分完成,通過 緩衝區回讀線程。

你需要用正確的read()大小,工作線程的數量,並通過周圍的緩衝區的數目進行試驗。較大的read() s會更高效,但較大的緩衝區大小會使內存需求變大,並使得從工作線程獲得該緩衝區的延遲變得更加難以預測。您希望儘可能少地拷貝數據,所以您希望工作線程直接在從文件讀取的緩衝區上工作。

+0

*不使用mmap *的前提似乎是*僅使用一次數據*。我沒有讀到這個問題。 – Zulan

+0

@Zulan你能否解釋一下你從什麼地方讀取數據將從文件中讀取多次的問題? –

+0

我也沒有讀過。我所讀的全部是字面意思*「做某事」*。 – Zulan

4

即使每個8K塊的處理都很重要(缺少OCR處理),I/O仍是瓶頸。除非能夠安排到由以前的操作中已緩存文件的部分....

如果系統是在運行上可以是專用的問題:

  1. 獲取文件大小(fstat
  2. 分配一個大小的緩衝區。
  3. 打開並將整個文件讀入緩衝區。
  4. 找出如何爲每個線程分割數據並分離線程。
  5. 算法的時間。

然後,使用異步讀取對其進行修改。請參閱man aio_readman 7 aio以瞭解需要完成的工作。

+1

如果你想要這樣讀取文件,我會添加使用直接IO。像這樣的處理的兩個缺點是1)內存要求 - 文件必須適合內存和2)延遲 - 直到整個文件被讀取才開始處理。不過,這當然是最簡單和最可維護的方法。 –