Linux系統(tǒng)IO中write原型為 ssize_t write(int filedes, const void * buff, size_t nbytes) ;
當調(diào)用write寫數(shù)據(jù)的時候,調(diào)用完成后write直接返回,但是磁盤是個慢速設(shè)備,操作系統(tǒng)會將數(shù)據(jù)保存在內(nèi)核中的緩沖區(qū)中,并負責異步地將數(shù)據(jù)寫至磁盤。當然如果此時系統(tǒng)宕機了則會丟失數(shù)據(jù)。write是系統(tǒng)調(diào)用,每次調(diào)用都會陷入內(nèi)核,所以選取一個合適的塊長度buffsize,并盡量減少它的調(diào)用可以優(yōu)化效率。在ANSI C的標準IO中我們調(diào)用printf/fprintf/fputs等會以流的方式進行處理,我們只需要寫入流中,而不用像write一樣選擇一個buffsize,因為標準IO庫幫我們處理了很多細節(jié),例如緩沖區(qū)分配,以優(yōu)化長度執(zhí)行IO等。這樣的話就會減少wirte/read系統(tǒng)調(diào)用的數(shù)量,提高效率。但是與此同時會引入另外一個問題:數(shù)據(jù)拷貝,例如當使用函數(shù)fgets和fputs時,通常需要經(jīng)過兩次緩沖區(qū):一次是標準IO緩沖區(qū),還有一次是調(diào)用read和write的內(nèi)核緩沖區(qū)。但是總的來說使用標準IO相對于系統(tǒng)IO來說接口簡單,且效率相當。
標準IO提供了三種類型的緩沖區(qū):全緩存,行緩存和不帶緩存,全緩存只有在緩沖區(qū)滿時才會主動flush,通常用在對一個磁盤文件IO。行緩存在緩沖區(qū)中遇到換行符就會flush,還有一種情況是需要從標準輸入輸出得到輸入數(shù)據(jù)時也會flush緩沖區(qū),行緩存一般用在交互的終端中。不帶緩存則相當于直接 write系統(tǒng)調(diào)用輸出,標準出錯流stderr通常是不帶緩存的,這就使得出錯信息可以盡快顯示出來。除了默認的flush條件外,顯式調(diào)用fflush函數(shù)和程序正常終止時也會flush緩沖區(qū)。我們可以使用setbuf/setvbuf來更改默認的緩沖區(qū)長度,參見APUE 5.4節(jié)。
在使用標準IO的程序中,當我們將一個標準輸出重新定向到一個文件時,會將行緩存變?yōu)槿彺?,在某些情況下可能會導(dǎo)致一些非預(yù)期錯誤,比如調(diào)用printf(“*****\n”)時,當以交互方式運行該程序時,會正常輸出。但是當將標準輸出重新定向到一個文件時,緩沖區(qū)區(qū)變?yōu)槿彺?,printf就不會正常輸出,該行數(shù)據(jù)仍在緩沖區(qū)中。如果此時再fork一個子進程,數(shù)據(jù)空間被復(fù)制到子進程中時,該緩沖區(qū)數(shù)據(jù)也被復(fù)制到子進程中。接著在子進程中如果輸出則會刷新之前在緩沖區(qū)的內(nèi)容,產(chǎn)生一些非預(yù)期的輸出。
在網(wǎng)絡(luò)編程中,應(yīng)該直接使用系統(tǒng)IO,標準IO為提升性能而引入緩沖機制增加了網(wǎng)絡(luò)應(yīng)用程序的復(fù)雜性。并且,某種意義上說標準IO流是全雙工的,能同時執(zhí)行輸入和輸出,然而對流的限制和對套接字的限制,有時候會互相沖突。(參見CSAPP P611)
延伸閱讀
- ssh框架 2016-09-30
- 阿里移動安全 [無線安全]玩轉(zhuǎn)無線電——不安全的藍牙鎖 2017-07-26
- 消息隊列NetMQ 原理分析4-Socket、Session、Option和Pipe 2024-03-26
- Selective Search for Object Recognition 論文筆記【圖片目標分割】 2017-07-26
- 詞向量-LRWE模型-更好地識別反義詞同義詞 2017-07-26
- 從棧不平衡問題 理解 calling convention 2017-07-26
- php imagemagick 處理 圖片剪切、壓縮、合并、插入文本、背景色透明 2017-07-26
- Swift實現(xiàn)JSON轉(zhuǎn)Model - HandyJSON使用講解 2017-07-26
- 阿里移動安全 Android端惡意鎖屏勒索應(yīng)用分析 2017-07-26
- 集合結(jié)合數(shù)據(jù)結(jié)構(gòu)來看看(二) 2017-07-26