日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

标准输入输出 stdio 流缓冲 buffering in standard streams

發(fā)布時間:2023/12/10 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 标准输入输出 stdio 流缓冲 buffering in standard streams 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.


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)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。