摘要:寫(xiě)緩存與寫(xiě)磁盤(pán)先看下寫(xiě)文件操作的流程結(jié)構(gòu)圖磁盤(pán)緩存是物理內(nèi)存的一部分,專(zhuān)門(mén)供操作系統(tǒng)用作讀寫(xiě)磁盤(pán)的緩沖之用。這印證了前面的說(shuō)法,字符串在文件關(guān)閉前只在磁盤(pán)緩存里,還未真正寫(xiě)到磁盤(pán)上,所以讀進(jìn)程無(wú)法讀出。
多進(jìn)程讀寫(xiě)同一個(gè)文件的問(wèn)題
不考慮文件內(nèi)容的錯(cuò)亂,多進(jìn)程是可以同時(shí)讀寫(xiě)一個(gè)文件的。當(dāng)一個(gè)進(jìn)程在寫(xiě),讀的進(jìn)程能否讀到最新的內(nèi)容,取決于最新的內(nèi)容是否真正寫(xiě)到了磁盤(pán)上。
寫(xiě)緩存與寫(xiě)磁盤(pán)先看下寫(xiě)文件操作的流程結(jié)構(gòu)圖:
磁盤(pán)緩存是物理內(nèi)存的一部分,專(zhuān)門(mén)供操作系統(tǒng)用作讀寫(xiě)磁盤(pán)的緩沖之用。磁盤(pán)緩存與“硬盤(pán)自帶的緩存”是不一樣的概念,它的大小是可以動(dòng)態(tài)設(shè)置的,而不像硬盤(pán)緩存在出廠的時(shí)候固定就是32M或64M。
我們通常用到的寫(xiě)文件API,其實(shí)是寫(xiě)到磁盤(pán)緩存上,可用python語(yǔ)言做一個(gè)實(shí)驗(yàn):
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
我們?cè)谟?w選項(xiàng)寫(xiě)hehe之后不會(huì)立刻關(guān)閉文件,而是sleep了10s,方便使用-r選項(xiàng)去讀文件,讀的時(shí)候我們發(fā)現(xiàn),除非文件關(guān)閉,否則讀不出任何內(nèi)容。這印證了前面的說(shuō)法,hehe字符串在文件關(guān)閉前只在磁盤(pán)緩存里,還未真正寫(xiě)到磁盤(pán)上,所以讀進(jìn)程無(wú)法讀出。
如何確保寫(xiě)到磁盤(pán)上而不只是磁盤(pán)緩存里呢?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,確保內(nèi)容確實(shí)更新到了磁盤(pán)。
fsync的幫助也指出了這一點(diǎn):
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.
所謂的“內(nèi)部緩存”就是磁盤(pán)緩存,強(qiáng)制更新到磁盤(pán),linux下用的是大家熟知的fsync,windows下則是_commit函數(shù)。
我們將寫(xiě)的代碼改成:
if opt == "-w": with open("1.txt", "w") as writer: writer.write("hehe ") writer.flush() os.fsync(writer.fileno()) time.sleep(10)
果然,讀進(jìn)程就能在文件尚未關(guān)閉時(shí)讀到hehe字符串了。
但是,fsync是要慎用的,因?yàn)槊織l內(nèi)容都強(qiáng)制刷新到磁盤(pán),雖然非常可靠,卻會(huì)帶來(lái)性能的急劇下降,我們可以在上述例子的基礎(chǔ)上改成寫(xiě)10萬(wàn)條字符串,對(duì)比“普通寫(xiě)”與“fsync寫(xiě)”的效率,會(huì)發(fā)現(xiàn)后者的耗時(shí)是前者的數(shù)千倍甚至是上萬(wàn)倍!這也正是redis的AOF日志雖然提供了fsync級(jí)別的磁盤(pán)同步卻不建議我們使用的原因(也因此redis的日志做不到絕對(duì)的單點(diǎn)可靠)。
這里還有一個(gè)疑問(wèn),按python的文檔,flush并不一定能將最新的內(nèi)容更新到磁盤(pán)上,我們查看java file API的文檔,發(fā)現(xiàn)也有類(lèi)似的說(shuō)法。這是為何?我個(gè)人的猜測(cè),flush只是簡(jiǎn)單的把磁盤(pán)緩存的內(nèi)容放到磁盤(pán)驅(qū)動(dòng)程序的寫(xiě)請(qǐng)求隊(duì)列里就返回,本質(zhì)上是異步的,而fsync除了放內(nèi)容到寫(xiě)請(qǐng)求隊(duì)列還會(huì)等待磁盤(pán)驅(qū)動(dòng)程序的返回結(jié)果,本質(zhì)上是同步的。由于fsync還要額外經(jīng)歷:等待寫(xiě)請(qǐng)求到隊(duì)列首部+磁盤(pán)驅(qū)動(dòng)程序調(diào)用磁盤(pán)控制器+磁盤(pán)控制器寫(xiě)到物理磁盤(pán)等步驟,自然就拖慢了fsync的速度。
進(jìn)程內(nèi)緩存與磁盤(pán)緩存進(jìn)程內(nèi)緩存指的是我在寫(xiě)磁盤(pán)緩存前,在自己的程序里再做一個(gè)緩存,將多條消息累積到一定的大小,再一次提交給磁盤(pán)緩存,這樣能提升寫(xiě)的效率。java里一般要在FileWriter之上再套一層BufferedWriter寫(xiě)入,就是這個(gè)用途,實(shí)測(cè)下來(lái),也能有一倍的效率提升。
python語(yǔ)言里沒(méi)有BufferedWriter,對(duì)于10萬(wàn)條字符串的寫(xiě)可以考慮別的方法,比如我們可以每500條拼成一個(gè)大的字符串再做寫(xiě)入,實(shí)測(cè)也有一倍的效率提升。
不過(guò),如同前面的“普通寫(xiě)”與“fsync寫(xiě)”一樣,效率的提升不是全無(wú)代價(jià),它往往伴隨著可靠性的降低。進(jìn)程內(nèi)緩存是屬于某個(gè)進(jìn)程的,一旦該進(jìn)程突然core掉,進(jìn)程內(nèi)緩存就會(huì)丟失,從用戶層面看來(lái),就是我明明已經(jīng)write好了的數(shù)據(jù),很可能并未寫(xiě)到磁盤(pán)里。相比之下,磁盤(pán)緩存就更可靠一些,因?yàn)樗怯刹僮飨到y(tǒng)管理的,與進(jìn)程無(wú)關(guān),除非是機(jī)器斷電,否則它不會(huì)丟失數(shù)據(jù),也就是說(shuō),即使我的進(jìn)程core掉,之前write的內(nèi)容依然可以安全到達(dá)磁盤(pán)上。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/41073.html
摘要:寫(xiě)緩存與寫(xiě)磁盤(pán)先看下寫(xiě)文件操作的流程結(jié)構(gòu)圖磁盤(pán)緩存是物理內(nèi)存的一部分,專(zhuān)門(mén)供操作系統(tǒng)用作讀寫(xiě)磁盤(pán)的緩沖之用。這印證了前面的說(shuō)法,字符串在文件關(guān)閉前只在磁盤(pán)緩存里,還未真正寫(xiě)到磁盤(pán)上,所以讀進(jìn)程無(wú)法讀出。 多進(jìn)程讀寫(xiě)同一個(gè)文件的問(wèn)題 不考慮文件內(nèi)容的錯(cuò)亂,多進(jìn)程是可以同時(shí)讀寫(xiě)一個(gè)文件的。當(dāng)一個(gè)進(jìn)程在寫(xiě),讀的進(jìn)程能否讀到最新的內(nèi)容,取決于最新的內(nèi)容是否真正寫(xiě)到了磁盤(pán)上。 寫(xiě)緩存與寫(xiě)磁盤(pán) 先...
摘要:從最開(kāi)始的到封裝后的都在試圖解決異步編程過(guò)程中的問(wèn)題。為了讓編程更美好,我們就需要引入來(lái)降低異步編程的復(fù)雜性。寫(xiě)一個(gè)符合規(guī)范并可配合使用的寫(xiě)一個(gè)符合規(guī)范并可配合使用的理解的工作原理采用回調(diào)函數(shù)來(lái)處理異步編程。 JavaScript怎么使用循環(huán)代替(異步)遞歸 問(wèn)題描述 在開(kāi)發(fā)過(guò)程中,遇到一個(gè)需求:在系統(tǒng)初始化時(shí)通過(guò)http獲取一個(gè)第三方服務(wù)器端的列表,第三方服務(wù)器提供了一個(gè)接口,可通過(guò)...
摘要:的翻譯文檔由的維護(hù)很多人說(shuō),阮老師已經(jīng)有一本關(guān)于的書(shū)了入門(mén),覺(jué)得看看這本書(shū)就足夠了。前端的異步解決方案之和異步編程模式在前端開(kāi)發(fā)過(guò)程中,顯得越來(lái)越重要。為了讓編程更美好,我們就需要引入來(lái)降低異步編程的復(fù)雜性。 JavaScript Promise 迷你書(shū)(中文版) 超詳細(xì)介紹promise的gitbook,看完再不會(huì)promise...... 本書(shū)的目的是以目前還在制定中的ECMASc...
摘要:可以通過(guò)大數(shù)據(jù)生態(tài)的一系列工具生態(tài)來(lái)解決大數(shù)據(jù)問(wèn)題數(shù)據(jù)分片主要有兩種方式哈希和范圍。哈希的問(wèn)題是范圍查詢支持不佳,范圍的問(wèn)題是可能冷熱數(shù)據(jù)不均。 后端好書(shū)閱讀與推薦系列文章:后端好書(shū)閱讀與推薦后端好書(shū)閱讀與推薦(續(xù))后端好書(shū)閱讀與推薦(續(xù)二)后端好書(shū)閱讀與推薦(續(xù)三)后端好書(shū)閱讀與推薦(續(xù)四)后端好書(shū)閱讀與推薦(續(xù)五)后端好書(shū)閱讀與推薦(續(xù)六) Elasticsearch權(quán)威指南 El...
摘要:可以通過(guò)大數(shù)據(jù)生態(tài)的一系列工具生態(tài)來(lái)解決大數(shù)據(jù)問(wèn)題數(shù)據(jù)分片主要有兩種方式哈希和范圍。哈希的問(wèn)題是范圍查詢支持不佳,范圍的問(wèn)題是可能冷熱數(shù)據(jù)不均。 后端好書(shū)閱讀與推薦系列文章:后端好書(shū)閱讀與推薦后端好書(shū)閱讀與推薦(續(xù))后端好書(shū)閱讀與推薦(續(xù)二)后端好書(shū)閱讀與推薦(續(xù)三)后端好書(shū)閱讀與推薦(續(xù)四)后端好書(shū)閱讀與推薦(續(xù)五)后端好書(shū)閱讀與推薦(續(xù)六) Elasticsearch權(quán)威指南 El...
閱讀 1772·2021-11-18 13:20
閱讀 1163·2021-10-11 10:59
閱讀 2995·2021-08-24 10:01
閱讀 3509·2019-08-29 14:21
閱讀 3359·2019-08-29 14:15
閱讀 3527·2019-08-26 12:23
閱讀 3348·2019-08-26 11:46
閱讀 3355·2019-08-26 11:35