2011-07-07 122 views
3

我有一個要求,我必須緩衝大量數據(以GB爲單位),以備將來使用。 由於沒有足夠的RAM可用於緩衝這麼大量的數據,因此我決定將這些數據存儲在一個文件中。將數據寫入文件:fflush()需要很長時間

現在這裏的缺陷是,在我將數據寫入文件時,其他線程可能需要「緩衝」數據,因此每次寫入數據時都必須刷​​新文件流。準確地說,數據是我作爲預先記錄的數據(如TiVo)緩衝的視頻幀,其他線程可能或可能不想在任何給定的時間點寫入它,但是當它們這樣做時,它們將從文件fread和處理幀。

在一般情況下,fwrite - fflush組合需要大約150 us,但偶爾(並且相當有規律),組合需要超過1.5秒。我不能負擔得起,因爲我必須實時處理幀。

我有很多問題在這裏:

  1. 是我在文件中緩存數據的方法正確嗎?我有什麼替代方案?

  2. 任何想法爲什麼fwrite-fflush操作在某些場合突然需要更多時間?請注意,在1.5秒後,它會恢復到150 us。

回答

2

至於#2:大多數現代文件系統使用btree方法來管理當今巨大HD中的目錄和數據節點的數量。與所有的樹木一樣,它們有時需要平衡。發生這種情況時,不會發生任何更改,這就是系統鎖定的原因。通常,由於操作系統的巨大緩存,這並不是什麼大問題,但是你是一個受到傷害的角落案例。

你能做些什麼呢?有兩種方法:

  1. 使用套接字進行通信,並保留最後的N幀在RAM(即從來沒有把它們寫入磁盤,或者使用獨立的進程將其寫入到磁盤)。

  2. 不要寫新文件,覆蓋現有的文件。由於所有數據塊的位置是事先知道的,因此在寫入時FS中不會有重組。它也會更快一點。所以這個想法是創建一個巨大的文件或使用原始分區,然後覆蓋它。當您點擊文件末尾時,請回到開始位置並重復。

缺點:

有了辦法#1,你可以失去幀。另外,您必須確保所有客戶端都能夠快速讀取和處理數據,否則服務器可能會被阻止。

使用#2,您必須找到一種方法告訴讀者當前「文件結束」的位置。

所以也許混合的方法是最好的:

  1. 創建一個巨大的文件(幾個GB)。如果一個文件不夠,請創建幾個文件。
  2. 打開套接字
  3. 將數據寫入文件。如果你到達文件末尾,試着定位0並繼續寫入(像循環緩衝區)。
  4. 同花順數據
  5. 通過socket

考慮使用內存映射文件發送新數據給讀者的開始和金額;這將使一切變得更簡單。

+0

關於您對使用內存映射文件的評論,可以將幾個GB的文件映射到內存?我有512 MB內存在我的處置。另外,內存映射如何使事情變得簡單? – puffadder

+0

是的,只要您的CPU地址空間可以處理它,文件大小並不重要。使用32位CPU,您可以管理大約3.5GB文件,使用64位CPU,文件大小無關緊要。至於簡單:http://en.wikipedia.org/wiki/Memory-mapped_file基本上,它允許您訪問文件,就好像它是內存中的一個字節數組。 –

1

除了內存和磁盤,還沒有其他選項,只有變化。我認爲這種方法是合理的:您正在獲得非常好的文件系統性能。

額外偶爾的時間很可能是由於尋找更多的自由空間(它保持短名單,但用盡時,需要更昂貴的搜索),並將其分配到文件的文件系統。如果這是原因,請以最大大小預先分配文件,並使用隨機I/O(fopen (fn, "r+"))寫入文件,以便它不截斷文件長度。

這可能有助於穩定文件的另一種技術的I/O時間是寫在文件偏移量,其被對準以一個扇區邊界的每個幀緩衝器中。這樣,文件系統不必處理奇怪的偏移寫操作,首先從扇區中讀取以保留不會被覆蓋的內容。