我試圖找出什麼是在Windows中編寫文件的最佳方法。爲此,我一直在用內存映射進行一些測試,試圖找出發生了什麼以及我應該如何組織事物...內存映射的IO概念細節
場景:該文件旨在用於單個進程,在多個線程中。你應該看到一個線程作爲工作在文件存儲上的工作者;其中一些會閱讀,一些會寫 - 在某些情況下,文件會增長。我希望我的狀態能夠在流程和操作系統崩潰中倖存下來。文件可能很大,例如:1 TB。
在MSDN上閱讀了很多內容後,我掀起了一個小小的測試案例。我基本上做的是以下幾點:
- 打開使用
FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH
文件(CreateFile
)。 - 使用某種文件增長機制在文件上構建mmap文件句柄(
CreateFileMapping
)。 - 使用多個扇區大小(從
STORAGE_PROPERTY_QUERY
)映射內存區域(MapViewOfFile
)。我打算使用的模式是READ + WRITE。
到目前爲止,我一直無法弄清楚如何完全使用這些構造(像diskmon
這樣的工具不會有很好的理由),所以我決定在這裏問一下。我基本上想知道的是:我如何最好地將這些結構用於我的場景?
如果我理解正確,這或多或少是正確的方法;然而,我不確定CreateFileMapping
與MapViewOfFile
的確切作用,以及它是否可以在多個線程中工作(例如寫入磁盤時寫入的順序)。
- 我打算按照(1)每個進程打開一次文件。
- 每個線程,我打算根據(2)爲整個文件創建一個mmap文件句柄。如果我需要增長文件,我會估計需要多少空間,關閉句柄並使用
CreateFileMapping
重新打開它。 - 雖然工作人員正在做它的事情,它需要的文件的部分。所以,我打算使用
MapViewOfFile
(似乎限制爲2 GB),對它進行處理並再次取消映射。
問題:
- 我是否正確地理解這些概念?
- 什麼時候物理讀取數據並寫入磁盤?所以,當我有一個在(3)中寫入1 MB數據的循環時,它會在之後寫入那個數據unmap調用嗎?或者,當我在另一個頁面中記憶時,它會寫入數據嗎? (畢竟,磁盤是塊設備,所以在某些時候我們必須寫一個塊...)
- 這個工作可以在多個線程中使用嗎?這是關於電話本身 - 我不確定他們是否會錯誤,如果你有 - 100名工人。
- 我明白(寫入)數據可以立即在其他線程中使用(除非它是遠程文件),這意味着我應該小心讀/寫併發。如果我打算寫東西,然後更新一個單物理塊頭(表明讀者應該從現在開始使用另一個指針) - 那麼是否保證將數據寫入之前到頭?
- 如果我使用1個文件或多個文件(當然假設它們在同一個物理設備上),它會影響嗎?
當你需要FILE_FLAG_WRITE_THROUGH和「生存操作系統崩潰」時,使用MMF是完全不合適的。您無法準確確定何時將MMF更改刷新到磁盤。不要這樣做。 –
@HansPassant有趣。我開始研究內存映射,因爲我在一些論文中看到一些數據庫將它用於磁盤IO(並且它們根據ACID保證'耐久性')。我還在PostgreSQL bugreports(https://www.postgresql.org/message-id/[email protected])上讀到他們停止使用'FlushFileBuffers'非常糟糕。所以,如果兩者都出來了 - 你在這裏建議作爲解決方案? – atlaste
使用WriteFile和ReadFile有什麼問題?既然你已經把緩衝關掉了,在我看來他們提供了你要找的保證,至少就操作系統而言。 (底層硬件可能會也可能不會尊重這些保證,如果您希望對電源故障也很強大,但是如果沒有,您可以做的事情也不多。) –