《LINUX入門:Linux后臺開發(fā)之IO緩沖區(qū)管理》要點(diǎn):
本文介紹了LINUX入門:Linux后臺開發(fā)之IO緩沖區(qū)管理,希望對您有用。如果有疑問,可以聯(lián)系我們。
Linux體系IO中write原型為? ssize_t write(int? filedes, const void * buff, size_t nbytes) ;
當(dāng)調(diào)用write寫數(shù)據(jù)的時候,調(diào)用完成后write直接返回,但是磁盤是個慢速設(shè)備,操作系統(tǒng)會將數(shù)據(jù)保留在內(nèi)核中的緩沖區(qū)中,并負(fù)責(zé)異步地將數(shù)據(jù)寫至磁盤.當(dāng)然如果此時系統(tǒng)宕機(jī)了則會丟失數(shù)據(jù).write是系統(tǒng)調(diào)用,每次調(diào)用都會陷入內(nèi)核,所以選取一個合適的塊長度buffsize,并盡量減少它的調(diào)用可以優(yōu)化效率.在ANSI C的標(biāo)準(zhǔn)IO中我們調(diào)用printf/fprintf/fputs等會以流的方式進(jìn)行處理,我們只需要寫入流中,而不用像write一樣選擇一個buffsize,因?yàn)闃?biāo)準(zhǔn)IO庫幫我們處理了很多細(xì)節(jié),例如緩沖區(qū)分配,以優(yōu)化長度執(zhí)行IO等.這樣的話就會減少wirte/read系統(tǒng)調(diào)用的數(shù)量,提高效率.但是與此同時會引入另外一個問題:數(shù)據(jù)拷貝,例如當(dāng)使用函數(shù)fgets和fputs時,通常需要經(jīng)過兩次緩沖區(qū):一次是標(biāo)準(zhǔn)IO緩沖區(qū),還有一次是調(diào)用read和write的內(nèi)核緩沖區(qū).但是總的來說使用標(biāo)準(zhǔn)IO相對于系統(tǒng)IO來說接口簡單,且效率相當(dāng).
標(biāo)準(zhǔn)IO提供了三種類型的緩沖區(qū):全緩存,行緩存和不帶緩存,全緩存只有在緩沖區(qū)滿時才會主動flush,通常用在對一個磁盤文件IO.行緩存在緩沖區(qū)中遇到換行符就會flush,還有一種情況是必要從標(biāo)準(zhǔn)輸入輸出得到輸入數(shù)據(jù)時也會flush緩沖區(qū),行緩存一般用在交互的終端中.不帶緩存則相當(dāng)于直接 write系統(tǒng)調(diào)用輸出,標(biāo)準(zhǔn)出錯流stderr通常是不帶緩存的,這就使得出錯信息可以盡快顯示出來.除了默認(rèn)的flush條件外,顯式調(diào)用fflush函數(shù)和程序正常終止時也會flush緩沖區(qū).我們可以使用setbuf/setvbuf來更改默認(rèn)的緩沖區(qū)長度,參見APUE 5.4節(jié).
在使用標(biāo)準(zhǔn)IO的程序中,當(dāng)我們將一個標(biāo)準(zhǔn)輸出重新定向到一個文件時,會將行緩存變?yōu)槿彺?在某些情況下可能會導(dǎo)致一些非預(yù)期錯誤,好比調(diào)用printf(“*****\n”)時,當(dāng)以交互方式運(yùn)行該程序時,會正常輸出.但是當(dāng)將標(biāo)準(zhǔn)輸出重新定向到一個文件時,緩沖區(qū)區(qū)變?yōu)槿彺?printf就不會正常輸出,該行數(shù)據(jù)仍在緩沖區(qū)中.如果此時再fork一個子進(jìn)程,數(shù)據(jù)空間被復(fù)制到子進(jìn)程中時,該緩沖區(qū)數(shù)據(jù)也被復(fù)制到子進(jìn)程中.接著在子進(jìn)程中如果輸出則會刷新之前在緩沖區(qū)的內(nèi)容,產(chǎn)生一些非預(yù)期的輸出.
在網(wǎng)絡(luò)編程中,應(yīng)該直接使用系統(tǒng)IO,尺度IO為提升性能而引入緩沖機(jī)制增加了網(wǎng)絡(luò)應(yīng)用程序的復(fù)雜性.并且,某種意義上說尺度IO流是全雙工的,能同時執(zhí)行輸入和輸出,然而對流的限制和對套接字的限制,有時候會互相沖突.(參見CSAPP P611)
某些高級的網(wǎng)絡(luò)庫中(比如說muduo庫)在使用系統(tǒng)IO的基礎(chǔ)上會創(chuàng)建自己的緩沖區(qū),贊助用戶屏蔽系統(tǒng)IO的某些不便,例如調(diào)用write發(fā)送大量數(shù)據(jù)的時候,發(fā)送緩沖區(qū)滿時需要應(yīng)用層等待,read接收數(shù)據(jù)的時候粘包和數(shù)據(jù)接受的緩慢.當(dāng)增加應(yīng)用層緩沖區(qū)后,由網(wǎng)絡(luò)庫處理這些實(shí)現(xiàn)細(xì)節(jié),簡化用戶操作.
Linux還提供了零拷貝技術(shù)來減少內(nèi)存拷貝,進(jìn)而提升效率,我們知道利用read/write從磁盤發(fā)送數(shù)據(jù)到網(wǎng)卡會經(jīng)過四次拷貝操作:當(dāng)應(yīng)用程序需要訪問某塊數(shù)據(jù)的時候,操作系統(tǒng)內(nèi)核會先檢查這塊數(shù)據(jù)是不是因?yàn)榍耙淮螌ο嗤募脑L問而已經(jīng)被存放在操作系統(tǒng)內(nèi)核地址空間的緩沖區(qū)內(nèi),如果在內(nèi)核緩沖區(qū)中找不到這塊數(shù)據(jù),Linux 操作系統(tǒng)內(nèi)核會先將這塊數(shù)據(jù)從磁盤讀出來放到操作系統(tǒng)內(nèi)核的緩沖區(qū)里.如果這個數(shù)據(jù)讀取操作是由 DMA 完成的,那么在 DMA 進(jìn)行數(shù)據(jù)讀取的這一過程中,CPU 只需要進(jìn)行緩沖區(qū)管理,以及創(chuàng)建和處理 DMA ,除此之外,CPU 不需要再做更多的事情,DMA 執(zhí)行完數(shù)據(jù)讀取操作之后,會通知操作系統(tǒng)做進(jìn)一步的處理.Linux 操作系統(tǒng)會根據(jù) read系統(tǒng)調(diào)用指定的應(yīng)用程序地址空間的地址,把這塊數(shù)據(jù)存放到哀求這塊數(shù)據(jù)的應(yīng)用程序的地址空間中去,待用戶對數(shù)據(jù)完成操作后,操作系統(tǒng)需要將數(shù)據(jù)再一次從用戶應(yīng)用程序地址空間的緩沖區(qū)拷貝到與網(wǎng)絡(luò)堆棧相關(guān)的內(nèi)核緩沖區(qū)中去,這個過程也是需要占用 CPU 的.數(shù)據(jù)拷貝操作結(jié)束以后,數(shù)據(jù)會被打包,然后發(fā)送到網(wǎng)絡(luò)接口卡上去.從上面的描述可以看出,在這種傳統(tǒng)的數(shù)據(jù)傳輸過程中,數(shù)據(jù)至少發(fā)生了四次拷貝操作,即便是使用了 DMA 來進(jìn)行與硬件的通訊,CPU 仍然需要訪問數(shù)據(jù)兩次.
(ps:記得之前看過一個面試題說是printf輸出過程經(jīng)過幾次緩沖區(qū),現(xiàn)在年夜家明白了吧!)
使用零拷貝技術(shù)可以避免數(shù)據(jù)在系統(tǒng)內(nèi)核地址空間的緩沖區(qū)和用戶應(yīng)用程序地址空間的緩沖區(qū)進(jìn)行拷貝.有時候,應(yīng)用程序在數(shù)據(jù)傳輸?shù)倪^程中不需要對數(shù)據(jù)進(jìn)行拜訪,傳輸?shù)臄?shù)據(jù)可以不用復(fù)制到用戶應(yīng)用區(qū),直接通過內(nèi)核發(fā)送到網(wǎng)卡就可以,這樣可以提高性能,而此時就需要零拷貝技術(shù).linux下可以用mmap,sendfile,splice實(shí)現(xiàn)零拷貝.具體參見? Linux 中的零拷貝技術(shù) ?.
本文永遠(yuǎn)更新鏈接地址:
《LINUX入門:Linux后臺開發(fā)之IO緩沖區(qū)管理》是否對您有啟發(fā),歡迎查看更多與《LINUX入門:Linux后臺開發(fā)之IO緩沖區(qū)管理》相關(guān)教程,學(xué)精學(xué)透。維易PHP學(xué)院為您提供精彩教程。
轉(zhuǎn)載請注明本頁網(wǎng)址:
http://www.fzlkiss.com/jiaocheng/12105.html