2012-06-19 113 views
2

我有一個二進制文件,其中包含信息塊(我將其稱爲數據包)。每個數據包由一個固定長度的頭部和一個可變長度的主體組成。我必須從包頭本身確定身體的長度。我的任務是從文件中讀取這些數據包並對它們執行一些操作。目前我正在執行此任務,如下所示:Java - 並行讀取二進制文件

  • 將文件作爲隨機訪問文件打開並轉到特定的起始位置(用戶指定的起始位置)。從這個位置讀取第一個數據包。在一個循環
    • 讀取下一個數據包
    • 執行我的操作 執行具體操作
    • 那麼這個推移,直到我打文件標誌的結束。

正如您可以猜到,當文件大小是巨大的,連續讀取每個數據包並處理它是一個耗時的事情。我想以某種方式將這個操作(即數據包生成操作)並行化並將其放入某個阻塞隊列中,然後從隊列中並行檢索每個數據包並執行我的操作。

有人可以建議我怎麼可以並行生成這些數據包?

+0

每個數據包頭文件中的位置(第一個之後)是否取決於前面的數據包的大小? –

+0

@Ted:不是。我根據讀取字節的特定簽名來檢測下一個數據包頭的開始。它會在前一個數據包結束後的某處出現,但不會出現在任何特定位置。 – Sujay

回答

5

您應該只有一個線程在文件中按順序讀,因爲我假設該文件位於一個驅動器。讀取文件受限於您的IO速度,因此在CPU中並行化沒有意義。事實上,由於常規硬盤驅動器專爲順序IO而設計,因此非順序讀取實際上會顯着降低性能。對於讀入的每個數據包,應該將該對象放入線程安全隊列中。

現在您可以開始並行處理數據包。創建多個線程並讓它們分別從隊列中讀取數據包。每個線程都應該進行處理並將其放入一些「完成」隊列中。

IO線程讀完文件後,應設置一個標誌,以便在隊列爲空時工作線程停止。

+0

+1,儘管現代SSD可能會使連續文件的並行讀取仍然比順序讀取更快。 – sarnold

+0

@sarnold:這可能是對的。雖然我沒有足夠的經驗對w/SSD架構做出任何說明,但P – tskuzzy

+0

+1用於阻止多線程讀取,這對性能非常重要。 –

0

我猜已知的快速方法是使用java.nio.MappedByteBuffer

+0

這聽起來像是一個簡單的內存映射。如何使用它來發現存儲在非標準化字節邊界上的數據包? – sarnold

+0

如果頭部有長度,至少可以跳過數據包 - 如果不是,則執行並行掃描並調整!這絕對是一種將塊預加載到內存並掃描它們比使用文件指針更快的方法,並且提前 –

3

如果您在使用盤片(即不是SSD)時使用磁盤,那麼沒有任何一個線程讀取該文件是沒有意義的,因爲您所要做的只是將磁盤抖動,導致磁盤臂引入毫秒延遲。如果你有一個固態硬盤它是一個不同的故事,你可以平行閱讀。

相反,你應該有一個線程從文件中讀取數據,並創建數據包,然後執行以下操作:

  • 等待對已初始化爲某編號的共享信號「A」(將是你「最大緩衝的分組」計數)
  • 鎖定的共享對象
  • 分組附加到一個鏈表
  • 信號的另一個共享信號「B」(這一個跟蹤分組在緩衝器中的計數)

然後,可以有許多其他的線程執行以下操作:在「B」旗語

  • 等待(以確保有將要處理的數據包)
  • 鎖定共享對象
  • 做在鏈表getFirst()和該分組存儲在本地變量
  • 信號旗語「A」,以允許另一分組到緩衝的包列表

這將確保您通過以連續的順序對數據包進行條帶化(儘快從磁盤中讀取數據包),並確保您一次處理多個數據包而無需輪詢。

+0

謝謝@AnthonyM您的建議!我猜你們和上一個答案都指向同一方向,即並行處理數據包,而不是並行訪問文件。 – Sujay