2010-01-26 65 views
5

我想提出一個看似簡單的問題,我無法找到答案無處。 是否有FAST用於文件輸入和/或輸出的現代算法,可以使用所有符合標準的C++編譯器進行編譯,適用於所有操作系統,無需外部庫?快速跨平臺算法讀取/寫入文件在C + +

  1. 我發現,最快的方法就是使用內存映射文件,但不會做的原因,我們希望在所有平臺上的工作
  2. 我們不能使用API​​,如Win32 API中的同一段代碼因爲這將使它具體的平臺
  3. 我不想使用c,我希望算法只是純粹的C++代碼與STL如果可行的話,不是一些醜陋的c與混合asm hack/trick
  4. 框架或外部不屬於標準C++的庫不應該像wxWidgets,Qt,MFC等一樣使用。
  5. 大這整個問題的empasis是,該算法是FAST成爲可能,隨着內存映射文件做它的速度線的東西,甚至更快的將是巨大的,但我知道這是不可能的

你有沒有見過除我以外的其他人研究過的東西? 這樣的算法甚至可能嗎?

感謝您的任何建議

回答

9

有以下限制:

可以與所有符合標準的C++編譯器進行編譯,並適用於所有的操作系​​統無需外部庫的要求?

你幾乎限制了自己的標準庫文件IO功能。也許POSIX函數(取決於你正在考慮的「所有符合標準的C++編譯器」的子集)。

如果他們對你來說不夠快,你將不得不放棄一些限制。

+1

同意。唯一的C++標準文件I/O來自標準庫,即。頭文件''或''。如果你想要快速的文件I/O,最重要的是**不**一次讀取/寫入一個字節的文件,而是一次讀取/寫入大塊。 – stakx 2010-01-26 00:47:10

+0

可以用iostream一次讀取整個文件嗎?那會提供性能優勢,我不這麼認爲?不是cstdio的c頭? – user258883 2010-01-26 01:02:51

+2

一次讀取整個文件仍然比映射到內存慢。 – 2010-01-26 01:11:35

9

這與「算法」無關。

當涉及到將數據寫入文件時,您處於操作系統的擺佈之中 - 內存映射文件是「快速」的,因爲您只是寫入內存,並且操作系統會同步回到內存它自己的時間。如果操作系統不支持它,那麼在這方面你就不太好運 - 除非你想實現你自己的內存映射層。

順便說一句,POSIX有mmap,所以如果你限制自己POSIX兼容系統,你沒事。

2

幾點:

  • 這有什麼好做的算法。
  • 想要定位所有操作系統並不是一個非常有效率的目標(在您測試它之前,您的代碼不能在特定平臺上運行),這是不可能的。相反,我會專注於一些可行的操作系統 - 比如說POSIX + Win32。
  • 在這種情況下,您可以執行內存映射,例如通過爲Windows實現mmap()(在MapViewOfFile()等之上) - 如果您需要某些靈感,git源代碼具有Windows的mmap實現)
  • 如果你不能使用內存映射,我建議使用普通的C文件API而不是C++的文件流,如果性能是一個大問題。儘管C++的流可能對某些操作具有更高的性能,但實際上它比較慢。
  • 但是,爲了獲得良好的性能,通常可以「足夠好」,只要確保您以理智的方式處理數據即可。依次讀取數據,不重新讀取等。完美是好的敵人;)
+0

@kusma:我很想看看C的'stdio'和C++的'iostream'功能之間的性能比較。你有沒有可能將我指向這些資源?因爲我曾經看過C++'iostream'庫源代碼(更具體地說,是MinGW附帶的實現),並且有一種印象,即它實際上只是一個非常簡單(基於模板)的C文件I/O功能。因此,我不希望看到任何顯着的表現差異。 – stakx 2010-01-26 00:51:13

+0

上帝的敵人? Yikes ... :) – 2010-01-26 01:12:17

+0

stakx:不幸的是,沒有。結果很長一段時間沒有了。在一位朋友報告使用std :: istream(與C API相比)的GCC/Linux顯着減速之後,我在2001年左右做了一些關於MSVC的分析。 IIRC,我們都發現性能下降大致相同,約爲30%。不過,這可能是記憶讓我誤解了數字。 德魯:對不起,我的意思是「撒旦的敵人」,當然;) – kusma 2010-01-26 01:46:49

0

其他海報是正確的,因爲性能總是與通用性(跨平臺)不一致。但是,通常情況下,您可以通過「緩衝」輸入來獲得最佳結果 - 使用fread()讀取相對較大的數據塊並處理這些數據。

我知道這是一個非常基本的和一般的答案,但這是關於具體的,因爲您可以得到沒有更具體的平臺特定,或更多地瞭解您正在處理的特定輸入。

1

按照文件系統塊大小的倍數(或冪次方)的順序讀取可能會有所幫助。然後在塊存儲在內存時挑選數據。他們在某處測試了各種塊大小的性能。我希望我能再次找到它。

你也可以嘗試擁有一個專用線程來讀取文件中的數據塊,另一個數據操作在內存中進行(當然還有正確的同步)。這允許您在阻止文件讀取調用時使用CPU來處理數據。

無論如何,如果你給這些想法一個嘗試,請讓我們知道,如果你注意到一個區別。您的基準測試的實際結果會很有趣。

+0

大多數硬盤使用的塊大小是512字節的倍數。對於較大的硬盤,它可能是1024或更大。 – 2010-01-26 17:50:15

+0

上面/下面的層使用的緩衝區大小可能與文件系統不同。嘗試不同的2的冪(不要把自己限制在512/1024,一直到256kiB)。我記得4kiB是在Linux的其中一個層中使用的魔術數字,但我不記得在哪裏。對不起,我不能更具體。 – 2010-01-26 18:18:32

+0

4k是文件系統塊的默認大小。 – 2010-01-26 19:59:52

1

快速IO一般可以歸結爲兩點:

  1. 最大限度地減少數據複製
  2. 最小化內核/用戶上下文切換

最重要IO技術,試圖解決一個或另一個。 IO知道的最快的跨平臺代碼是Perl IO系統。我建議看看the source。 Perl黑客已經花了數十年在儘可能多的平臺上儘可能快地獲得他們的IO。

4

爲了對「操作系統的憐憫」提出另一種觀點,複製文件的大部分開銷取決於操作系統。碎片文件比碎片整理文件需要更多時間來讀取。沒有用於檢測碎片文件的通用或標準C++函數。

在C++中的最快方法:

std::ifstream in_file; 
std::ofstream out_file; 

out_file << in_file.rdbuf(); 

您可以通過使用關鍵字「拷貝文件rdbuf」在網上搜索找到更多的細節。上面的片段將複製留給操作系統,但可以跨所有平臺移植。通過讀入C++ i/o流,你可以設置讀緩衝區的大小,或者讓它使用你自己的緩衝區。

更快的文件複製需要特定於平臺的功能,例如DMA傳輸。使用線程和多重緩衝,可以加快速度;但是C++不支持線程(有一個事實上的標準,POSIX,它支持線程)。一個線程將讀入緩衝區,而另一個線程從緩衝區寫入。