标准输入输出 stdio 流缓冲 buffering in standard streams
From : http://www.pixelbeat.org/programming/stdio_buffering/
譯者:李秋豪
我發(fā)現(xiàn)找出標(biāo)準(zhǔn)流用的是什么緩沖是一件困難的事。
例如下面這個使用unix shell 管道的例子:
$ command1 | command2下圖顯示了shell fork了兩個進(jìn)程并通過一個管道將他們聯(lián)系起來。在這個連接中移動使用了三個緩沖.
內(nèi)核中的緩沖區(qū)室友pipe系統(tǒng)函數(shù)生成的,它的大小取決于操作系統(tǒng)的頁大小。我們無法也沒必要控制這個緩沖區(qū)的大小,因為它會立即轉(zhuǎn)送數(shù)據(jù)(至少在linux上是這樣)。[更新:這個pipe buffer 已經(jīng)變化為 circular buffers (16 x 4KiB)并且有一個新的 proposed patch 使得它的大小是動態(tài)的]
另外兩個緩沖是關(guān)于流的,為了提高效率,僅僅在第一次使用流的時候申請緩沖區(qū)空間。三個標(biāo)準(zhǔn)流(stdin, stdout, stderr)會在幾乎所有的unix GNU C程序開始執(zhí)行自動被創(chuàng)建,新的流也可以被創(chuàng)建用來連接文件、套接字、管道等等。你可以通過控制緩沖策略(無緩沖,行緩沖,滿緩沖)來控制數(shù)據(jù)的讀寫方法。我使用這個程序來確定標(biāo)準(zhǔn)流的默認(rèn)緩沖區(qū)的特性:
/* Output info about the default buffering parameters* applied by libc to stdin, stdout and stderr.* Note the info is sent to stderr, as redirecting it* makes no difference to its buffering parameters.* Note gnulib has fbufmode() to make this portable.*/ #include <stdio_ext.h> #include <unistd.h> #include <stdlib.h>FILE* fileno2FILE(int fileno){switch(fileno) {case 0: return stdin;case 1: return stdout;case 2: return stderr;default: return NULL;} }const char* fileno2name(int fileno){switch(fileno) {case 0: return "stdin";case 1: return "stdout";case 2: return "stderr";default: return NULL;} }int main(void) {if (isatty(0)) {fprintf(stderr,"Hit Ctrl-d to initialise stdin\n");} else {fprintf(stderr,"Initialising stdin\n");}char data[4096];fread(data,sizeof(data),1,stdin);if (isatty(1)) {fprintf(stdout,"Initialising stdout\n");} else {fprintf(stdout,"Initialising stdout\n");fprintf(stderr,"Initialising stdout\n");}fprintf(stderr,"Initialising stderr\n"); //redundantint i;for (i=0; i<3; i++) {fprintf(stderr,"%6s: tty=%d, lb=%d, size=%d\n",fileno2name(i),isatty(i),__flbf(fileno2FILE(i))?1:0,__fbufsize(fileno2FILE(i)));}return EXIT_SUCCESS; }默認(rèn)緩沖策略:
- stdin總是緩沖的
- stderr總是無緩沖的
- 如果stdout是終端的話緩沖是行緩沖的,否則是滿緩沖的。(補(bǔ)充一下,GNU里面定義的可交互設(shè)備,顯然終端是可交互設(shè)備)
默認(rèn)緩沖大小:
- 緩沖大小只會直接影響緩沖策略
- 內(nèi)核的pipe buffer 已經(jīng)變化為 circular buffers (16 x 4KiB)并且有一個新的 proposed patch 使得它的大小是動態(tài)的
- 如果stdin/stdout 連接的是交互設(shè)備那么默認(rèn)大小是1024,否則是4096
stdio 輸出緩沖的問題
現(xiàn)在來考慮一個問題:數(shù)據(jù)源的信息是間隔發(fā)送的,并且接受者希望立即收到新產(chǎn)生的數(shù)據(jù)。
例如,一個人想要過濾 tcpdump -l 或者 tail -f 的輸出等等(注意有一些過濾器比如sort要求一次緩存所有數(shù)據(jù)到內(nèi)部,所以這里不能使用)。
考慮下面這個操作,從動態(tài)網(wǎng)絡(luò)日志終端數(shù)據(jù)中過濾出不一樣的IP地址:
$ tail -f access.log | cut -d' ' -f1 | uniq問題在于,如果按照上面這個命令,我們將不能實時的看到增加的主機(jī)IP,示例圖如下:
高亮的緩沖區(qū)導(dǎo)致了問題的發(fā)生。由于該緩存區(qū)連接了一個管道緩沖區(qū),他會等到數(shù)據(jù)達(dá)到4096字節(jié)后再作為一個塊傳送給uniq。注意到tail的標(biāo)準(zhǔn)輸出也有這個問題,但是tail -f調(diào)用會自動清除緩沖區(qū)當(dāng)有新的數(shù)據(jù)輸入時,所以這里不會產(chǎn)生影響( tcpdump -l, grep --line-buffered sed --unbuffered 也是這樣)。另外,由于uniq標(biāo)準(zhǔn)輸出連接的是一個可交互設(shè)備,所以當(dāng)有新的一行數(shù)據(jù)到達(dá)時也會自動清除緩沖區(qū),不會產(chǎn)生影響。
stdio 輸入緩沖問題
正如向stdout一樣,stdin也使用緩沖區(qū)以增加效率。
如果一個一個字節(jié)的讀入顯然會有更多控制的空間,但是這樣是不實際的。
考慮以下命令:
$ printf "one\ntwo\nthree\n" | ( sed 1q ; sed 1q ; sed 1q ) one(譯者注:這里的q是sed流編輯器的退出命令,1q表示當(dāng)輸出到達(dá)第一行結(jié)束時退出。參考The q or quit command)
正如你所見到的,第一個sed進(jìn)程讀取了所有數(shù)據(jù),導(dǎo)致后面的sed沒辦法讀入數(shù)據(jù)。注意僅僅將stdin緩沖區(qū)設(shè)置為行緩沖是沒有用的,因為只有當(dāng)輸出緩沖區(qū)被清除的時候才會產(chǎn)生控制效果(譯者注,如果沒有輸出的話,第一個sed還是會”一行一行的把輸入數(shù)據(jù)讀完)。以上的sed標(biāo)準(zhǔn)輸入都是行緩沖Reading lines from stdin.通常你只能控制一個進(jìn)程能否從stdin讀入數(shù)據(jù),或者讀入特定規(guī)模的數(shù)據(jù)然后禁止讀入。以下是這樣的一個例子:
$ printf "one\ntwo\nthree\n" | ( ssh localhost printf 'zero\\n' ; cat ) zero(譯者注:后面的cat命令用于從stdin中讀取數(shù)據(jù)輸出到屏幕,防止printf的輸出存儲在緩沖區(qū)中。)
這個遠(yuǎn)程printf命令并不會從stdin讀取數(shù)據(jù)(譯者注:'zero\n'是參數(shù)),但是ssh client并不知道這個,所以他會讀取前面printf傳入的數(shù)據(jù)即stdin中讀取數(shù)據(jù)。為了告訴ssh遠(yuǎn)程命令不需要讀入數(shù)據(jù),可以加上-n這個參數(shù):
$ printf "one\ntwo\nthree\n" | ( ssh -n localhost printf 'zero\n' ; cat ) zero one two three常見的經(jīng)歷是你想要吧ssh放在后臺當(dāng)你知道遠(yuǎn)程命令不會讀取數(shù)據(jù)的時候(利于常見的圖像化程序),設(shè)置ssh client阻止讀入數(shù)據(jù)可以防止遠(yuǎn)程應(yīng)用程序停滯。你可以通過-f參數(shù)告訴ssh忽略stdin并且fork到后臺。例如:ssh -fY localhost xterm(譯者注:-Y Enables trusted X11 forwarding)。
stdio 緩沖控制
省略...(關(guān)鍵詞:stdbuf, BUF_X_=Y where X = 0 (stdin), 1 (stdout), 2 (stderr) )
轉(zhuǎn)載于:https://www.cnblogs.com/liqiuhao/p/7669007.html
總結(jié)
以上是生活随笔為你收集整理的标准输入输出 stdio 流缓冲 buffering in standard streams的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python3 unicode字符串_【
- 下一篇: linux用echo显示欢迎信息,我使用