後台開發之IO緩衝區管理

2021-09-20 15:56:51 字數 1449 閱讀 8540

linux系統io中write原型為  

ssize_t write(int  filedes, const void * buff, size_t nbytes) ;

當呼叫write寫資料的時候,呼叫完成後write直接返回,但是磁碟是個慢速裝置,作業系統會將資料儲存在核心中的緩衝區中,並負責非同步地將資料寫至磁碟。當然如果此時系統宕機了則會丟失資料。write是系統呼叫,每次呼叫都會陷入核心,所以選取乙個合適的塊長度buffsize,並儘量減少它的呼叫可以優化效率。在ansi c的標準io中我們呼叫printf/fprintf/fputs等會以流的方式進行處理,我們只需要寫入流中,而不用像write一樣選擇乙個buffsize,因為標準io庫幫我們處理了很多細節,例如緩衝區分配,以優化長度執行io等。這樣的話就會減少wirte/read系統呼叫的數量,提高效率。但是與此同時會引入另外乙個問題:資料拷貝,例如當使用函式fgets和fputs時,通常需要經過兩次緩衝區:一次是標準io緩衝區,還有一次是呼叫read和write的核心緩衝區。但是總的來說使用標準io相對於系統io來說介面簡單,且效率相當。

標準io提供了三種型別的緩衝區:全快取,行快取和不帶快取,全快取只有在緩衝區滿時才會主動flush,通常用在對乙個磁碟檔案io。行快取在緩衝區中遇到換行符就會flush,還有一種情況是需要從標準輸入輸出得到輸入資料時也會flush緩衝區,行快取一般用在互動的終端中。不帶快取則相當於直接 write系統呼叫輸出,標準出錯流stderr通常是不帶快取的,這就使得出錯資訊可以盡快顯示出來。除了預設的flush條件外,顯式呼叫fflush函式和程式正常終止時也會flush緩衝區。我們可以使用setbuf/setvbuf來更改預設的緩衝區長度,參見apue 5.4節。

在使用標準io的程式中,當我們將乙個標準輸出重新定向到乙個檔案時,會將行快取變為全快取,在某些情況下可能會導致一些非預期錯誤,比如呼叫printf(「*****\n」)時,當以互動方式執行該程式時,會正常輸出。但是當將標準輸出重新定向到乙個檔案時,緩衝區區變為全快取,printf就不會正常輸出,該行資料仍在緩衝區中。如果此時再fork乙個子程序,資料空間被複製到子程序中時,該緩衝區資料也被複製到子程序中。接著在子程序中如果輸出則會重新整理之前在緩衝區的內容,產生一些非預期的輸出。

某些高階的網路庫中(比如說muduo庫)在使用系統io的基礎上會建立自己的緩衝區,幫助使用者遮蔽系統io的某些不便,例如呼叫write傳送大量資料的時候,傳送緩衝區滿時需要應用層等待,read接收資料的時候粘包和資料接受的緩慢。當增加應用層緩衝區後,由網路庫處理這些實現細節,簡化使用者操作。

(ps:記得之前看過乙個面試題說是printf輸出過程經過幾次緩衝區,現在大家明白了吧!)

使用零拷貝技術可以避免資料在系統核心位址空間的緩衝區和使用者應用程式位址空間的緩衝區進行拷貝。有時候,應用程式在資料傳輸的過程中不需要對資料進行訪問,傳輸的資料可以不用複製到使用者應用區,直接通過核心傳送到網絡卡就可以,這樣可以提高效能,而此時就需要零拷貝技術。linux下可以用mmap,sendfile,splice實現零拷貝。

後台開發之IO緩衝區管理

linux系統io中write原型為 ssize t write int filedes,const void buff,size t nbytes 當呼叫write寫資料的時候,呼叫完成後write直接返回,但是磁碟是個慢速裝置,作業系統會將資料儲存在核心中的緩衝區中,並負責非同步地將資料寫至磁碟...

後台開發之IO緩衝區管理

linux系統io中write原型為 ssize t write int filedes,const void buff,size t nbytes 當呼叫write寫資料的時候,呼叫完成後write直接返回,但是磁碟是個慢速裝置,作業系統會將資料儲存在核心中的緩衝區中,並負責非同步地將資料寫至磁碟...

I O 基礎之緩衝區

緩衝區以及緩衝區是如何工作,是所有i o的基礎。輸入 輸出 就是把資料移進或移出緩衝區。程序執行i o操作,就是向作業系統發出請求,讓它要麼把緩衝區的資料排乾 寫 要麼用資料把緩衝區填滿 讀 程序使用這一機制處理所有資料進出操作。從磁碟讀資料到程序記憶體區 程序使用read 系統呼叫,要求其緩衝區被...