摘要:寫緩存與寫磁盤先看下寫文件操作的流程結構圖磁盤緩存是物理內存的一部分,專門供操作系統用作讀寫磁盤的緩沖之用。這印證了前面的說法,字符串在文件關閉前只在磁盤緩存里,還未真正寫到磁盤上,所以讀進程無法讀出。
多進程讀寫同一個文件的問題
不考慮文件內容的錯亂,多進程是可以同時讀寫一個文件的。當一個進程在寫,讀的進程能否讀到最新的內容,取決于最新的內容是否真正寫到了磁盤上。
寫緩存與寫磁盤先看下寫文件操作的流程結構圖:
磁盤緩存是物理內存的一部分,專門供操作系統用作讀寫磁盤的緩沖之用。磁盤緩存與“硬盤自帶的緩存”是不一樣的概念,它的大小是可以動態設置的,而不像硬盤緩存在出廠的時候固定就是32M或64M。
我們通常用到的寫文件API,其實是寫到磁盤緩存上,可用python語言做一個實驗:
if opt == "-w": with open("1.txt", "w") as writer: writer.write("hehe ") time.sleep(10) elif opt == "-r": with open("1.txt") as fp: for line in fp: line = line.rstrip() print line
我們在用-w選項寫hehe之后不會立刻關閉文件,而是sleep了10s,方便使用-r選項去讀文件,讀的時候我們發現,除非文件關閉,否則讀不出任何內容。這印證了前面的說法,hehe字符串在文件關閉前只在磁盤緩存里,還未真正寫到磁盤上,所以讀進程無法讀出。
如何確保寫到磁盤上而不只是磁盤緩存里呢?python文檔給出了建議:
file.flush() Flush the internal buffer. Note flush() does not necessarily write the file’s data to disk. Use flush() followed by os.fsync() to ensure this behavior.
文檔建議我們flush+fsync,確保內容確實更新到了磁盤。
fsync的幫助也指出了這一點:
os.fsync(fd) Force write of file with filedescriptor fd to disk. On Unix, this calls the native fsync() function; on Windows, the MS _commit() function. If you’re starting with a Python file object f, first do f.flush(), and then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
所謂的“內部緩存”就是磁盤緩存,強制更新到磁盤,linux下用的是大家熟知的fsync,windows下則是_commit函數。
我們將寫的代碼改成:
if opt == "-w": with open("1.txt", "w") as writer: writer.write("hehe ") writer.flush() os.fsync(writer.fileno()) time.sleep(10)
果然,讀進程就能在文件尚未關閉時讀到hehe字符串了。
但是,fsync是要慎用的,因為每條內容都強制刷新到磁盤,雖然非??煽浚瑓s會帶來性能的急劇下降,我們可以在上述例子的基礎上改成寫10萬條字符串,對比“普通寫”與“fsync寫”的效率,會發現后者的耗時是前者的數千倍甚至是上萬倍!這也正是redis的AOF日志雖然提供了fsync級別的磁盤同步卻不建議我們使用的原因(也因此redis的日志做不到絕對的單點可靠)。
這里還有一個疑問,按python的文檔,flush并不一定能將最新的內容更新到磁盤上,我們查看java file API的文檔,發現也有類似的說法。這是為何?我個人的猜測,flush只是簡單的把磁盤緩存的內容放到磁盤驅動程序的寫請求隊列里就返回,本質上是異步的,而fsync除了放內容到寫請求隊列還會等待磁盤驅動程序的返回結果,本質上是同步的。由于fsync還要額外經歷:等待寫請求到隊列首部+磁盤驅動程序調用磁盤控制器+磁盤控制器寫到物理磁盤等步驟,自然就拖慢了fsync的速度。
進程內緩存與磁盤緩存進程內緩存指的是我在寫磁盤緩存前,在自己的程序里再做一個緩存,將多條消息累積到一定的大小,再一次提交給磁盤緩存,這樣能提升寫的效率。java里一般要在FileWriter之上再套一層BufferedWriter寫入,就是這個用途,實測下來,也能有一倍的效率提升。
python語言里沒有BufferedWriter,對于10萬條字符串的寫可以考慮別的方法,比如我們可以每500條拼成一個大的字符串再做寫入,實測也有一倍的效率提升。
不過,如同前面的“普通寫”與“fsync寫”一樣,效率的提升不是全無代價,它往往伴隨著可靠性的降低。進程內緩存是屬于某個進程的,一旦該進程突然core掉,進程內緩存就會丟失,從用戶層面看來,就是我明明已經write好了的數據,很可能并未寫到磁盤里。相比之下,磁盤緩存就更可靠一些,因為它是由操作系統管理的,與進程無關,除非是機器斷電,否則它不會丟失數據,也就是說,即使我的進程core掉,之前write的內容依然可以安全到達磁盤上。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/41073.html
摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。寫一個符合規范并可配合使用的寫一個符合規范并可配合使用的理解的工作原理采用回調函數來處理異步編程。 JavaScript怎么使用循環代替(異步)遞歸 問題描述 在開發過程中,遇到一個需求:在系統初始化時通過http獲取一個第三方服務器端的列表,第三方服務器提供了一個接口,可通過...
摘要:的翻譯文檔由的維護很多人說,阮老師已經有一本關于的書了入門,覺得看看這本書就足夠了。前端的異步解決方案之和異步編程模式在前端開發過程中,顯得越來越重要。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。 JavaScript Promise 迷你書(中文版) 超詳細介紹promise的gitbook,看完再不會promise...... 本書的目的是以目前還在制定中的ECMASc...
摘要:可以通過大數據生態的一系列工具生態來解決大數據問題數據分片主要有兩種方式哈希和范圍。哈希的問題是范圍查詢支持不佳,范圍的問題是可能冷熱數據不均。 后端好書閱讀與推薦系列文章:后端好書閱讀與推薦后端好書閱讀與推薦(續)后端好書閱讀與推薦(續二)后端好書閱讀與推薦(續三)后端好書閱讀與推薦(續四)后端好書閱讀與推薦(續五)后端好書閱讀與推薦(續六) Elasticsearch權威指南 El...
摘要:可以通過大數據生態的一系列工具生態來解決大數據問題數據分片主要有兩種方式哈希和范圍。哈希的問題是范圍查詢支持不佳,范圍的問題是可能冷熱數據不均。 后端好書閱讀與推薦系列文章:后端好書閱讀與推薦后端好書閱讀與推薦(續)后端好書閱讀與推薦(續二)后端好書閱讀與推薦(續三)后端好書閱讀與推薦(續四)后端好書閱讀與推薦(續五)后端好書閱讀與推薦(續六) Elasticsearch權威指南 El...
閱讀 1755·2021-11-18 13:20
閱讀 1140·2021-10-11 10:59
閱讀 2987·2021-08-24 10:01
閱讀 3499·2019-08-29 14:21
閱讀 3351·2019-08-29 14:15
閱讀 3512·2019-08-26 12:23
閱讀 3342·2019-08-26 11:46
閱讀 3344·2019-08-26 11:35