簡體   English   中英

使用ofstream進行緩沖文本輸出以獲得性能

[英]Using ofstream for buffered text output to gain performance

我需要編寫一個程序,它將在輸出文件中寫入許多字符。 我的程序還需要編寫換行符以便更好地格式化。 我理解ofstream是一個緩沖流,如果我們為文件io使用緩沖流,我們就會獲得性能。 但是,如果我們使用std::endl ,輸出將被刷新,並且由於緩沖輸出,我們將失去任何潛在的性能增益。

我想如果我使用'\\n'作為新行,那么當我們將std::endl時,輸出將被刷新。 它是否正確? 是否有任何技巧可用於在文件輸出期間獲得性能提升?

注意:我想在文件寫入操作完成時刷新緩沖輸出。 我認為通過這種方式,我可以最小化文件I / O,從而獲得性能。

通常,如果需要最大性能,流類的用戶不應該弄亂流的刷新:當流滿時,流內部刷新緩沖區。 這實際上比等待所有輸出都准備好更有效,特別是對於大文件:緩沖數據在仍然可能在內存中時寫入。 如果您創建一個巨大的緩沖區,並且只有在虛擬內存系統將部分數據放入光盤而不是文件時才寫入。 它需要從光盤讀取並再次寫入。

關於std::endl要點是人們濫用它一個行結束導致緩沖區刷新,他們不知道性能影響。 std::endl是讓人們控制在合理的點上刷新文件。 為了使其有效,他們需要知道他們在做什么。 可悲的是,有太多的人不知道std::endl做了什么廣告宣傳它作為一個行結尾使用它在許多地方使用它是完全錯誤的。

也就是說,以下是您可能希望嘗試提高性能的一些事項。 我假設你需要格式化輸出(使用std::ofstream::write()不會給你)。

  • 顯然,除非必須,否則不要使用std::endl 如果編寫代碼已經存在並且在許多地方使用std::endl ,其中一些可能在你的控制之外,你可以使用一個過濾流緩沖區,它使用其合理大小的內部緩沖區,並且不會將調用轉發到它的sync()函數到底層流緩沖區。 雖然這涉及額外的副本,但這比一些虛假的沖洗更好,因為這些是更高的數量級。
  • 雖然它不應該對std::ofstream s產生影響,但是調用std::ios_base::sync_with_stdio(false)會影響某些實現的性能。 如果這會產生影響,您可能希望使用不同的IOstream實現,因為在性能方面可能存在更多錯誤。
  • 確保在調用其always_noconv()時使用std::localestd::codecvt<...>返回true 這可以通過使用std::use_facet<std::codecvt<char, char, stdd::mbstate_t> >(out.get_loc()).always_noconv()輕松檢查。 您可以使用std::locale("C")來獲取應該為true的std::locale
  • 一些語言環境實現使用非常低效的數字方面實現,即使它們相當不錯, std::num_put<char> facet的默認實現仍可能執行您不需要的操作。 特別是如果您的數字格式相當簡單,即您不繼續更改格式標記,您沒有替換字符的映射(即您不使用有趣的std::ctype<char> facet)等等。使用自定義std::num_put<char> facet是合理的:為整數類型創建一個快速但簡單的格式化函數是相當容易的,而對於不在內部使用snprintf()浮點也是一個很好的格式化函數。

有些人建議使用內存映射文件,但這只有在事先知道目標文件的大小時才合理。 如果是這種情況,這是一種提高性能的好方法,否則就不值得了。 請注意,您可以通過創建使用內存映射接口的自定義std::streambuf ,將流格式化與內存映射文件(或更常見地,使用任何類型的輸出接口)一起使用。 我發現內存映射在與std::istream s一起使用時有時會有效。 在許多情況下,差異並不重要。

很久以前我編寫了自己的IOStreams和locales實現,它沒有遇到上面提到的一些性能問題(它可以在我的網站上找到,但它有點陳舊,我已經有近10年的時間了)。 有很多事情可以通過這個實現來改進,但我沒有最新的實現,我准備在某處發布。 很快,希望 - 這是我近10年來一直在思考的事情,盡管......

打印\\n將不會(必須)刷新輸出,而打印std::endlstd::flush會。

如果你想要快速寫入並且不關心數據是否存在,直到完成,那么用\\n進行所有寫操作並且不要擔心(因為關閉文件也會刷新流)。

如果你仍然沒有得到你想要的性能,你可以使用fstream :: read(char *,int) - 它允許你以任何你想要的大小塊讀取數據(嘗試更大的塊,看看它是否有幫助)。

是的, endl刷新流。 不要將它用於大文件。

還要確保設置流緩沖區 當沒有設置緩沖區 ,至少MSVC實現一次1個char復制到filebuf (請參閱streambuf::xsputn )。 這可能會使您的應用程序受CPU限制,從而導致I / O速率降低。

因此,在編寫代碼之前,請在代碼中添加以下內容:

char buf[256 * 1024];
mystream.rdbuf()->pubsetbuf(buf, sizeof(buf));

注意:您可以在此處找到完整的示例應用程序。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM