我們知道标準C中的檔案讀取的函數比如printf,fwrite等函數,實際都是調用OS級别的
API,比如LINUX下就是wirte,read函數,而write read函數在使用者态下是沒有緩沖的,
當然在核心态有OS CACHE/OS BUFFER,是以某些直接調用wirte,read的程式肯定會
配置設定一個緩沖區,特别是O_DIRECT這種方式下,核心态的OS CACHE和OS BUFFER沒用
這種情況下使用者态的BUFFER顯得更加重要,因為不可能一次讀一個位元組吧,那性能可想而知
而作為使用者态空間的STDIO也是這樣做的,它會為打開的檔案配置設定緩存,預設應該是8192位元組
如下圖摘自UNIX系統程式設計手冊 13章:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIn5GcugDMmJWOiJTZwUzMxUWYwkzM0QTZ1EmMhFDZ4EGZhV2NfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.png)
實際上我們可以使用setvbuf來設定某個打開檔案的緩沖大小及模式。
我們來看看原型:
int setvbuf(FILE *stream, char *buf, int mode, size_t size);
傳回0為成功,非零為失敗
FILE *stream:打開檔案的FILE*
char *buf:BUFFER的位址,如果為NULL,MODE為_IOLBF和_IOFBF則自動配置設定緩沖區
如果為_IONBF則不配置設定緩沖區
int mode:_IONBF不使用緩沖區,立即調用write/read,忽略buf和size為NULL和0,stderr屬于這個
_IOLBF使用行緩沖I/O,終端裝置預設為這種。要麼遇到換行符要麼緩沖滿才調用write/read,
stdin/stdout屬于這個。
_IOFBF采用全緩沖I/O,buffer滿才調用write/read,磁盤I/O屬于這個比如fwrite/fread
size_t size:緩沖大小
更簡單函數setbuf原型如下:
void setbuf(FILE *stream, char *buf);
相當于
setvbuf(fp,buf,(buf !=NULL)?_IOFBF:_IONBF,BUFSIZ);
如果buf=NULL則_IONBF打開不帶緩沖,或者調用全緩沖,BUFSIZ預設8192。
是以我們如果不想用緩沖直接:
setvbuf(fp,NULL)
即可。
現在回想一下fread
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
fread的時候我們通常要calloc一塊記憶體用于void *ptr,那麼現在我們想一下實際
上這個資料正常緩存到了3個地方
1、使用者配置設定的記憶體*ptr
2、STDIO的緩存預設8192
3、核心态OS CACHE
這視乎有點臃腫,我們可以想辦法簡化。事實上資料庫軟體有時候隻使用了使用者态
的一份緩存,而打開O_DIRECT來提高性能。
下面一個小程式可以驗證打開和關閉stdout緩沖的差別:
int main(void)
{
int i;
// setbuf(stdout,NULL);
for(i=0;i<10;i++)
{
printf("-");
sleep(1);
}
printf("\n");
}
差別就是是否使用setbuf,如果使用setbuf則 -符号會一個一個輸出,不使用會一起輸出
這就是STDIO緩存在作怪。