2013-03-19 35 views
3

我正在處理基於回調中的數據的回調函數,我想寫入不同的文件。C++多次寫入文件的高效方法

例如,在一次調用中,我可能想寫入january.csv,而在另一次調用不同數據時,它可能是july.csv。沒有預先確定的順序,它可能是每個回調中的任何月份,我無法事先知道。 january.csv(實際上所有的月份)都會被寫入多次。

這些回調發生得非常快,所以我需要這個代碼儘可能高效。

天真的方法,我會採取將每次使用下面的代碼:

ofstream fout; 
fout.open(month_string); 
fout<<data_string<<endl; 
fout.close(); 

的問題是,這似乎並沒有很有效的,因爲我不斷地打開/關閉month.csv文件。有沒有更快捷的方法可以讓january.csv,february.csv等所有的時間都開放,讓這個更快?

編輯:我正在寫入Linux上的/ dev/shm,所以I/O延遲並不是真正的問題。

+0

爲什麼不能有多個'std :: ofstream'對象?每個月一個?像他們的數組? – chrisaycock 2013-03-19 14:39:11

+0

這是可能的,但我的上面的例子是人爲設計的,實際上,我有超過12個ofstream物體,數量接近10,000。我將不得不在每個回調中循環10,000個數組,這比fout.open()和fout.close()慢。 – user788171 2013-03-19 14:56:28

+0

你真的爲每個回調寫入10K文件嗎?或者,你是否只爲每個回調寫入一個特定的文件?如果是後者,那麼你如何決定要寫入哪個文件?任何你可以從'std :: ofstream'對象的輸入中使用'std :: map'或'std :: unordered_map'的機會? – chrisaycock 2013-03-19 14:59:55

回答

0

我懷疑大多數系統將讓你有〜10K文件打開一次,這或多或少排除了剛剛開放的所有文件和書面形式向他們需要。因此,您可能只需要創建某種代理對象來爲每個文件緩衝數據,並且當緩衝區超出某個給定大小時,打開該文件,將數據寫入磁盤並關閉它再次。

我可以看到兩個相當簡單的方法。一個是自己編寫大部分代碼,使用stringstream作爲緩衝區。客戶端流到您的對象,它只是通過串流。然後檢查字符串流是否超過一定的長度,如果是,則將內容寫入磁盤並清空字符串流。

另一種方法是編寫自己的文件緩衝區對象,該對象實現sync以打開文件,寫入數據並再次關閉文件(文件通常將文件始終保持打開狀態)。

然後,您會將它們存儲在std::map(或std::unordered_map)中,以便您從文件名執行查找以查找匹配的代理對象。

+0

在Linux上,可以增加文件描述符限制以處理10k個同時打開的文件。 – user788171 2013-03-19 15:47:08

+0

@ user788171:理論上,當然。實際上,我懷疑有一些相當好的理由,它通常限於比這少很多,所以當你*可以*做到這一點時,你可能不想這樣做。 – 2013-03-19 15:49:59

2

您希望減少I/O調用次數,同時在調用它們時充分利用它們。

例如,緩存數據並將更大的塊寫入文件。您可能有另一個負責週期性地將緩衝區刷新到文件的線程。

無效率的基礎有兩個方面:等待硬盤驅動器初始化(快速啓動),第二種方法是定位文件和空白扇區以便寫入。不管數量多少你正在寫的數據。數據塊越大,有效寫入的時間就越多(當盤片旋轉時)。對於Flash/Thumb驅動器也是如此;拇指驅動器有一個開銷(解鎖,擦除等)。所以目標是通過大塊寫入來減少開銷。

你可能要考慮使用一個數據庫:Evaluating the need for database.

+0

忘了提及,我正在寫入內存(/ dev/shm),所以I/O延遲並不是真正的問題。 – user788171 2013-03-19 15:18:34

+0

同樣,您想要緩存數據並寫入大塊。例如,一個'ostream :: write'比許多'operator <<'更快。這可以通過向控制檯輸出常量文本來演示。首先,使用'operator <<'並觀察時間。現在把文本放到一個'static const char []'中,並且在數組中使用'ostream :: write'。 – 2013-03-19 15:24:46

+0

即使你正在寫回憶,我仍然認爲托馬斯馬修斯的建議是完美的設計。它不能滿足您的所有要求嗎? – 2013-03-19 15:24:57

0

我不認爲開遍地關閉相同的文件將是昂貴的。操作系統通常被設計爲通過在存儲器中緩存部分FS元數據來處理該用例。成本將主要是系統調用的上下文切換。另一方面,在10k文件上這樣做可能會耗盡操作系統緩存的能力。

您可以通過編寫順序所有輸出在一個單一的文件,其目標註解,形成期刊卸載了一下你身邊的FS工作。然後,另一個程序(FS補充程序)將負責打開該日誌,緩衝寫入命令(按文件分組),然後在緩衝區達到某個閾值時將其刷新到磁盤。您必須在期刊中標記已執行的命令爲已提交,以便在補充程序中斷並且必須恢復的情況下,它會知道還有什麼要完成的。


更新:

可以調整文件系統,支持在同一時間打開和10000個文件高速緩存,並把它處理的調度命令的問題(這是爲什麼FS 取得)。

你的問題是實際選擇正確的文件系統爲您的使用情況。我建議用不同的FS進行測試,看看哪一個表現最好。

唯一剩下的部分將有你的程序中使用std::map的文件名與他們的描述符(簡單)相關聯。

看到這麼調諧linux max open files,或者詢問有關該主題的一個問題,如果你不能找到一個對您的具體FS。