常常聽到有程序員會跟你討論:“我們在讀寫文件的時候,系統(tǒng)是有緩存的”。但實(shí)際上有一部分人把用戶進(jìn)程緩存區(qū)和系統(tǒng)空間緩存區(qū)的概念混淆了,包括這兩種緩沖區(qū)的用法和所要解決的問題,還有其它類似的概念。本文就來區(qū)分一下不同的緩沖區(qū)概念(主要針對類unix平臺)。
用戶進(jìn)程和操作系統(tǒng)的關(guān)系,首先我用一張圖來解釋“用戶進(jìn)程和操作系統(tǒng)的關(guān)系:
這是一個計算機(jī)系統(tǒng)運(yùn)行時的簡化模型,我們把所有運(yùn)行在操作系統(tǒng)上的進(jìn)程成為用戶進(jìn)程,它們都運(yùn)行在用戶空間(可以看到用戶空間有很多進(jìn)程)。把操作系統(tǒng)運(yùn)行的空間成為系統(tǒng)空間。
為什么將進(jìn)程分為用戶進(jìn)程和系統(tǒng)進(jìn)程,首先你一定聽說過內(nèi)核態(tài)和用戶態(tài)(kernel mode和user mode),在內(nèi)核態(tài)可以訪問系統(tǒng)資源,比如:
處理器cpu:cpu控制著一個程序的執(zhí)行。輸入輸出IO:linux有句話叫“一切都是流”,也就是所有輸入輸出設(shè)備的數(shù)據(jù),包括硬盤,內(nèi)存,終端都可以像流一樣操作。進(jìn)程管理:類似對進(jìn)程的創(chuàng)建,休眠,喚醒,釋放之類的調(diào)度。比如linux下的fork和windows下的CreateProcess()函數(shù)。內(nèi)存:包括內(nèi)存的申請,釋放等管理操作。設(shè)備:這個就是常常說的外設(shè)了,比如鼠標(biāo),鍵盤。計時器:計算機(jī)能計時是因?yàn)榫w振蕩器產(chǎn)生的電磁脈沖。那么所有的定時任務(wù)都是以它為基礎(chǔ)的。進(jìn)程間通信IPC:進(jìn)程之間是不能夠互相訪問內(nèi)存的,所以進(jìn)程與進(jìn)程之間的交互需要通信,而通信也是一種資源。網(wǎng)絡(luò)通信:網(wǎng)絡(luò)通信可以看做是進(jìn)程見通信的特殊形式。
注釋:fflush把進(jìn)程緩沖區(qū)的數(shù)據(jù)刷新到內(nèi)核緩沖區(qū),fsync把內(nèi)核緩沖區(qū)的數(shù)據(jù)刷新到物理媒介上。
而上面所說的這些系統(tǒng)資源,在用戶進(jìn)程中是無法被直接訪問的,只能通過操作系統(tǒng)來訪問,所以也把操作系統(tǒng)提供的這些功能成為:“系統(tǒng)調(diào)用”。
比如下圖,展示一個用戶通過shell控制計算機(jī)所經(jīng)過的數(shù)據(jù)流向:文件讀寫和終端控制,都是通過內(nèi)核進(jìn)行的。
提供這些限制的基礎(chǔ)就是cpu提供的內(nèi)核態(tài)和用戶態(tài)。比如intel x86 CPU有四種不同的執(zhí)行級別0-3,linux只使用了其中的0級和3級分別來表示內(nèi)核態(tài)和用戶態(tài)。
在用戶態(tài),不僅僅是系統(tǒng)資源了,就是別的進(jìn)程的內(nèi)存對于你來說,都是“透明的”(并不是沒辦法訪問,否則游戲作弊器怎么實(shí)現(xiàn)?)
用戶進(jìn)程緩存區(qū)
前面提到,用戶進(jìn)程通過系統(tǒng)調(diào)用訪問系統(tǒng)資源的時候,需要切換到內(nèi)核態(tài),而這對應(yīng)一些特殊的堆棧和內(nèi)存環(huán)境,必須在系統(tǒng)調(diào)用前建立好。而在系統(tǒng)調(diào)用結(jié)束后,cpu會從核心模式切回到用戶模式,而堆棧又必須恢復(fù)成用戶進(jìn)程的上下文。而這種切換就會有大量的耗時。
你看一些程序在讀取文件時,會先申請一塊內(nèi)存數(shù)組,稱為buffer,然后每次調(diào)用read,讀取設(shè)定字節(jié)長度的數(shù)據(jù),寫入buffer。(用較小的次數(shù)填滿buffer)。之后的程序都是從buffer中獲取數(shù)據(jù),當(dāng)buffer使用完后,在進(jìn)行下一次調(diào)用,填充buffer。所以說:用戶緩沖區(qū)的目的是為了減少系統(tǒng)調(diào)用次數(shù),從而降低操作系統(tǒng)在用戶態(tài)與核心態(tài)切換所耗費(fèi)的時間。除了在進(jìn)程中設(shè)計緩沖區(qū),內(nèi)核也有自己的緩沖區(qū)。
內(nèi)核緩存區(qū)
當(dāng)一個用戶進(jìn)程要從磁盤讀取數(shù)據(jù)時,內(nèi)核一般不直接讀磁盤,而是將內(nèi)核緩沖區(qū)中的數(shù)據(jù)復(fù)制到進(jìn)程緩沖區(qū)中。
但若是內(nèi)核緩沖區(qū)中沒有數(shù)據(jù),內(nèi)核會把對數(shù)據(jù)塊的請求,加入到請求隊(duì)列,然后把進(jìn)程掛起,為其它進(jìn)程提供服務(wù)。
等到數(shù)據(jù)已經(jīng)讀取到內(nèi)核緩沖區(qū)時,把內(nèi)核緩沖區(qū)中的數(shù)據(jù)讀取到用戶進(jìn)程中,才會通知進(jìn)程,當(dāng)然不同的io模型,在調(diào)度和使用內(nèi)核緩沖區(qū)的方式上有所不同,下一小結(jié)介紹。
你可以認(rèn)為,read是把數(shù)據(jù)從內(nèi)核緩沖區(qū)復(fù)制到進(jìn)程緩沖區(qū)。write是把進(jìn)程緩沖區(qū)復(fù)制到內(nèi)核緩沖區(qū)。當(dāng)然,write并不一定導(dǎo)致內(nèi)核的寫動作,比如os可能會把內(nèi)核緩沖區(qū)的數(shù)據(jù)積累到一定量后,再一次寫入。這也就是為什么斷電有時會導(dǎo)致數(shù)據(jù)丟失。所以說內(nèi)核緩沖區(qū),是為了在OS級別,提高磁盤IO效率,優(yōu)化磁盤寫操作。
流程
在《Unix網(wǎng)絡(luò)編程》中的五種io模型,也提到過進(jìn)程緩沖區(qū)和內(nèi)核緩沖區(qū)。因?yàn)檫@個并不是此篇文章的重點(diǎn),所以這里只對比阻塞模型和非阻塞。
對比阻塞和非阻塞,在阻塞io中,直到數(shù)據(jù)從內(nèi)核緩沖區(qū)拷貝到用戶緩沖區(qū)才通知用戶進(jìn)程調(diào)用完成并喚醒,而非阻塞,在輪訓(xùn)得知數(shù)據(jù)準(zhǔn)備好后,數(shù)據(jù)還是在內(nèi)核緩沖區(qū)中,等你去讀取,這也就是說數(shù)據(jù)準(zhǔn)備好,并不代表已經(jīng)讀好可以使用。當(dāng)然也不代表一定能讀。
緩存區(qū)和緩存
還有一部分人把緩沖區(qū)和緩存混淆,后來我明白這也是因?yàn)榉g導(dǎo)致的把兩種東西進(jìn)行混淆。緩沖區(qū)的英文是buffer,而緩存的應(yīng)為是cache。
CPU緩存(Cache Memory)是位于CPU與內(nèi)存之間的臨時存儲器,因?yàn)閏pu的計算速度要比內(nèi)存的讀寫速度快很多,而把這些可能會被重復(fù)訪問到的數(shù)據(jù)存儲于cpu緩存中,就會提高讀取速度??梢哉f緩存是cpu和內(nèi)存之間的臨時存儲器。
也就是說,buffer是因?yàn)闇p少調(diào)用次數(shù),集中調(diào)用,提高系統(tǒng)性能。而cache是將讀取過的數(shù)據(jù)保存起來,重新讀取時若命中(找到需要的數(shù)據(jù))就不要去讀硬盤了,若沒有命中就讀硬盤。而緩沖可以理解為內(nèi)存和硬盤之間的臨時存儲器,重點(diǎn)是寫的過程。
-
振蕩器
+關(guān)注
關(guān)注
28文章
3803瀏覽量
138809 -
緩沖
+關(guān)注
關(guān)注
0文章
51瀏覽量
17806 -
操作系統(tǒng)
+關(guān)注
關(guān)注
37文章
6684瀏覽量
123140 -
終端
+關(guān)注
關(guān)注
1文章
1106瀏覽量
29799
發(fā)布評論請先 登錄
相關(guān)推薦
評論