2017-06-22 73 views
0

我試圖找出什麼是在Windows中編寫文件的最佳方法。爲此,我一直在用內存映射進行一些測試,試圖找出發生了什麼以及我應該如何組織事物...內存映射的IO概念細節

場景:該文件旨在用於單個進程,在多個線程中。你應該看到一個線程作爲工作在文件存儲上的工作者;其中一些會閱讀,一些會寫 - 在某些情況下,文件會增長。我希望我的狀態能夠在流程和操作系統崩潰中倖存下來。文件可能很大,例如:1 TB。

在MSDN上閱讀了很多內容後,我掀起了一個小小的測試案例。我基本上做的是以下幾點:

  1. 打開使用FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH文件(CreateFile)。
  2. 使用某種文件增長機制在文件上構建mmap文件句柄(CreateFileMapping)。
  3. 使用多個扇區大小(從STORAGE_PROPERTY_QUERY)映射內存區域(MapViewOfFile)。我打算使用的模式是READ + WRITE。

到目前爲止,我一直無法弄清楚如何完全使用這些構造(像diskmon這樣的工具不會有很好的理由),所以我決定在這裏問一下。我基本上想知道的是:我如何最好地將這些結構用於我的場景?

如果我理解正確,這或多或少是正確的方法;然而,我不確定CreateFileMappingMapViewOfFile的確切作用,以及它是否可以在多個線程中工作(例如寫入磁盤時寫入的順序)。

  1. 我打算按照(1)每個進程打開一次文件。
  2. 每個線程,我打算根據(2)爲整個文件創建一個mmap文件句柄。如果我需要增長文件,我會估計需要多少空間,關閉句柄並使用CreateFileMapping重新打開它。
  3. 雖然工作人員正在做它的事情,它需要的文件的部分。所以,我打算使用MapViewOfFile(似乎限制爲2 GB),對它進行處理並再次取消映射。

問題:

  1. 我是否正確地理解這些概念?
  2. 什麼時候物理讀取數據並寫入磁盤?所以,當我有一個在(3)中寫入1 MB數據的循環時,它會在之後寫入那個數據unmap調用嗎?或者,當我在另一個頁面中記憶時,它會寫入數據嗎? (畢竟,磁盤是塊設備,所以在某些時候我們必須寫一個塊...)
  3. 這個工作可以在多個線程中使用嗎?這是關於電話本身 - 我不確定他們是否會錯誤,如果你有 - 100名工人。
  4. 我明白(寫入)數據可以立即在其他線程中使用(除非它是遠程文件),這意味着我應該小心讀/寫併發。如果我打算寫東西,然後更新一個單物理塊頭(表明讀者應該從現在開始使用另一個指針) - 那麼是否保證將數據寫入之前到頭?
  5. 如果我使用1個文件或多個文件(當然假設它們在同一個物理設備上),它會影響嗎?
+3

當你需要FILE_FLAG_WRITE_THROUGH和「生存操作系統崩潰」時,使用MMF是完全不合適的。您無法準確確定何時將MMF更改刷新到磁盤。不要這樣做。 –

+0

@HansPassant有趣。我開始研究內存映射,因爲我在一些論文中看到一些數據庫將它用於磁盤IO(並且它們根據ACID保證'耐久性')。我還在PostgreSQL bugreports(https://www.postgresql.org/message-id/[email protected])上讀到他們停止使用'FlushFileBuffers'非常糟糕。所以,如果兩者都出來了 - 你在這裏建議作爲解決方案? – atlaste

+0

使用WriteFile和ReadFile有什麼問題?既然你已經把緩衝關掉了,在我看來他們提供了你要找的保證,至少就操作系統而言。 (底層硬件可能會也可能不會尊重這些保證,如果您希望對電源故障也很強大,但是如果沒有,您可以做的事情也不多。) –

回答

-3

內存映射文件通常最適合READING;不寫。你面對的問題是你在做映射之前必須知道文件的大小。

你說:

在某些情況下,該文件將增長

這實際上排除了映射文件的存儲。

在Windoze上創建內存映射文件時,您正在創建自己的頁面文件並將一系列內存映射到該頁面文件。這往往是讀取二進制數據的最快方式,尤其是在文件連續的情況下。

對於寫入,內存映射文件存在問題。