中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

淺談帶緩沖I/O 和不帶緩沖I/O的區別與聯系

發布時間:2020-08-19 22:57:27 來源:腳本之家 閱讀:679 作者:jingxian 欄目:編程語言

這里搜集從網上看到的一些言論,自認為還是比較靠譜的,有些不靠譜的根據自己的理解進行了修正。

首先要明白不帶緩沖的概念:所謂不帶緩沖,并不是指內核不提供緩沖,而是只單純的系統調用,不是函數庫的調用。系統內核對磁盤的讀寫都會提供一個塊緩沖(在有些地方也被稱為內核高速緩存),當用write函數對其寫數據時,直接調用系統調用,將數據寫入到塊緩沖進行排隊,當塊緩沖達到一定的量時,才會把數據寫入磁盤。因此所謂的不帶緩沖的I/O是指進程不提供緩沖功能(但內核還是提供緩沖的)。每調用一次write或read函數,直接系統調用。
帶緩沖的I/O是指進程對輸入輸出流進行了改進,提供了一個流緩沖,當用fwrite函數網磁盤寫數據時,先把數據寫入流緩沖區中,當達到一定條件,比如流緩沖區滿了,或刷新流緩沖,這時候才會把數據一次送往內核提供的塊緩沖,再經塊緩沖寫入磁盤。(雙重緩沖)
因此,帶緩沖的I/O在往磁盤寫入相同的數據量時,會比不帶緩沖的I/O調用系統調用的次數要少。

看正常情況下,和磁盤交互的讀寫文件是怎么個流程!

當應用程序嘗試讀取某塊數據的時候,如果這塊數據已經存放在頁緩存中,那么這塊數據就可以立即返回給應用程序,而不需要經過實際的物理讀盤操作。當然,如果數據在應用程序讀取之前并未被存放在頁緩存中(也就是上面提到的內核高速緩存),那么就需要先將數據從磁盤讀到頁緩存中去。對于寫操作來說,應用程序也會將數據先寫到頁緩存中去(這里所說的寫到頁緩存中,如果是調用標準庫I/O進行寫,那么首先是寫到標準庫的緩沖區內,如果標準庫的緩沖區寫滿以后,在寫到頁緩沖內;如果是系統調用,那么直接寫到頁緩沖內),數據是否被立即寫到磁盤上去取決于應用程序所采用的寫操作機制:如果用戶采用的是同步寫機制,那么數據會立即被寫回到磁盤上,應用程序會一直等到數據被寫完為止;如果用戶采用的是延遲寫機制,那么應用程序就完全不需要等到數據全部被 寫回到磁盤,數據只要被寫到頁緩存中去就可以了。在延遲寫機制的情況下,操作系統會定期地將放在頁緩存中的數據刷到磁盤上。與異步寫機制不同的是,延遲寫機制在數據完全寫到磁盤上得時候不會通知應用程序,而異步寫機制在數據完全寫到磁盤上得時候是會返回給應用程序的。所以延遲寫機制本省是存在數據丟失的風險的,而異步寫機制則不會有這方面的擔心。

下面聊聊不帶緩沖的I/O

 不帶緩存,不是直接對磁盤文件進行讀取操作,像read()和write()函數,它們都屬于系統調用,只不過在用戶層沒有緩存,所以叫做無緩存IO,但對于內核來說,還是進行了緩存,只是用戶層看不到罷了。

帶不帶緩存是相對來說的,如果你要寫入數據到文件上時(就是寫入磁盤上),內核先將數據寫入到內核中所設的緩沖儲存器,假如這個緩沖儲存器的長度是100個字節,你調用系統函: 

ssize_t write (int fd,const void * buf,size_t count);

寫操作時,設每次寫入長度count=10個字節,那么你幾要調用10次這個函數才能把這個緩沖區寫滿,此時數據還是在緩沖區,并沒有寫入到磁盤,緩沖區滿時才進行實際上的IO操作,把數據寫入到磁盤上,所以上面說的“不帶緩存""不是沒有緩存而是沒有直寫進磁盤就是這個意思(既然沒有寫入磁盤,調用系統調用為何可以在文件中看到寫入的內容呢,因為內核控件是共享的)

那么,既然不帶緩存的操作實際在內核是有緩存器的,那帶緩存的IO操作又是怎么回事呢?

帶緩存IO也叫標準IO,符合ANSI C 的標準IO處理,不依賴系統內核,所以移植性強,我們使用標準IO操作很多時候是為了減少對read()和write()的系統調用次數,帶緩存IO其實就是在用戶層再建立一個緩存區,這個緩存區的分配和優化長度等細節都是標準IO庫代你處理好了,不用去操心,還是用上面那個例子說明這個操作過程:

上面說要寫數據到文件上,內核緩存(注意這個不是用戶層緩存區)區長度是100字節,我們調用不帶緩存的IO函數write()就要調用10次,這樣系統效率低,現在我們在用戶層建立另一個緩存區(用戶層緩存區或者叫流緩存),假設流緩存的長度是50字節,我們用標準C庫函數的fwrite()將數據寫入到這個流緩存區里面,流緩存區滿50字節后在進入內核緩存區,再調用系統函數write()將數據寫入到內核緩沖內,如果內核緩沖也被填滿,或者內核進行fflush操作,那么內核緩沖區內數據就別寫入到文件(實質是磁盤)上,看到這里,你用該明白一點,標準IO操作fwrite()最后還是要掉用無緩存IO操作write,這里進行了兩次調用fwrite()寫100字節也就是進行兩次系統調用write()。

如果看到這里還沒有一點眉目的話,那就比較麻煩了,希望下面兩條總結能夠幫上忙:

無緩存IO操作數據流向路徑:數據——內核緩存區——磁盤

標準IO操作數據流向路徑:數據——流緩存區——內核緩存區——磁盤

下面是一個網友的見解,以供參考:

不帶緩存的I/O對文件描述符操作,下面帶緩存的I/O是針對流的。

標準I/O庫就是帶緩存的I/O,它由ANSI C標準說明。當然,標準I/O最終都會調用上面的I/O例程。標準I/O庫代替用戶處理很多細節,比如緩存分配、以優化長度執行I/O等。

標準I/O提供緩存的目的就是減少調用read和write的次數,它對每個I/O流自動進行緩存管理(標準I/O函數通常調用malloc來分配緩存)。

下面的東西是我從網上查到的對這兩者的理解,我覺得還是很到位的:

以下主要討論關于open,write等基本系統IO的帶緩沖與不帶緩沖的差別

帶緩存的文件操作是標準C庫的實現,第一次調用帶緩存的文件操作函數時標準庫會自動分配內存并且讀出一段固定大小的內容存儲在緩存中。所以以后每次的讀寫操作并不是針對硬盤上的文件直接進行的,而是針對內存中的緩存的。何時從硬盤中讀取文件或者向硬盤中寫入文件有標準庫的機制控制。不帶緩存的文件操作通常都是系統提供的系統調用, 更加低級,直接從硬盤中讀取和寫入文件,由于IO瓶頸的原因,速度并不如意,而且原子操作需要程序員自己保證,但使用得當的話效率并不差。另外標準庫中的帶緩存文件IO 是調用系統提供的不帶緩存IO實現的。

“術語不帶緩沖指的是每個read和write都調用內核中的一個系統調用。所有的磁盤I/O都要經過內核的塊緩沖(也稱內核的緩沖區高速緩存),唯一例外的是對原始磁盤設備的I/O。既然read或write的數據都要被內核緩沖,那么術語“不帶緩沖的I/O“指的是在用戶的進程中對這兩個函數不會自動緩沖,每次read或write就要進行一次系統調用。“--------摘自<unix環境編程>

程序中用open和write打開創建并把“hello world“寫入文件test.txt,相應用fopen和fwrite操作文件test2.txt。程序執行到open和fopen之后,sleep 15秒,這時用ls查看生成了文件沒,這時用open打開的test.txt出現了,用fopen打開的的test2.txt也出現了;當程序執行完write和 fwrite之后,在15秒睡眠期間,用cat查看test.txt,其內容是“hello,world”;但是此時用cat查看test2.txt,其內容為空。睡眠結束后,執行了close(fd),此時再用cat查看test2.txt,發現其內容也有了:“hello,world”。該例子證明了open和write是不帶緩沖的,即程序一執行其io操作也立即執行,不會停留在系統提供的緩沖里,不需等到close操作完才執行。與之相比的fopen和fwrite則是帶緩沖的,(一般)要等到fclose操作完后才會執行。

相關的源碼示例如下:

#include <unistd.h>
#include <iostream>
#include <fcntl.h>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>

using namespace std;

int main(){
int fd;
FILE *file;
char *s="hello,world\n";
if((fd=open("test.txt",O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR))==-1){
cout<<"Error open file"<<endl;
return -1;
}
if((file=fopen("test2.txt","w"))==NULL){
cout<<"Error Open File."<<endl;
return -1;
}
cout<<"File has been Opened."<<endl;
sleep(15);
if(write(fd,s,strlen(s))<strlen(s)){
cout<<"Write Error"<<endl;

return -1;
}
if(fwrite(s,sizeof(char),strlen(s),file)<strlen(s)){
cout<<"Write Error in 2."<<endl;

return -1;
}
cout<<"After write"<<endl;

sleep(15);
cout<<"After sleep."<<endl;

close(fd);
return 0;
}

以 ssize_t write(int filedes, const void *buff, size_t nbytes)和size_t fwrite(const void *ptr, size_t size, size_t nobj, FILE *fp)來講講自己對unix系統下帶緩存的I/O和不帶緩存的I/O的區別。

首先要清楚一個概念,所謂的帶緩存并不是指上面兩個函數的buff參數

當將數據寫到文件上時,內核先將該數據寫到緩存,如果該緩存未滿,則并不將其排入輸出隊列,直到緩存寫滿或者內核再次需要重新使用此緩存時才將其排入輸入隊列,待其到達隊首,再進行實際的I/O操作,也就是此時才把數據真正寫到磁盤,這種技術叫延遲寫。

現在假設內核所設的緩存是100個字節,如果你使用write,且buff的size為10,當你要把9個同樣的buff寫到文件時,你需要調用9次write,也就是9次系統調用,此時也并沒有寫到硬盤,如果想立即寫到硬盤,調用fsync,可以進行實際的I/O操作。

標準I/O,也就是帶緩存的I/O采用 FILE*,FILE實際上包含了為管理流所需要的所有信息:實際I/O的文件描述符,指向流緩存的指針(標準I/O緩存,由malloc分配,又稱為用戶態進程空間的緩存,區別于內核所設的緩存),緩存長度,當前在緩存中的字節數,出錯標志等,假設流緩存的長度為50字節,把以上的數據寫到文件,則只需要2次系統調用(fwrite調用write系統調用),因為先把數據寫到流緩存,當其滿以后或者調用fflush時才填入內核緩存,所以進行了2次的系統調用write。

fflush將流所有未寫的數據送入(刷新)到內核(內核緩沖區),fsync將所有內核緩沖區的數據寫到文件(磁盤)。至于究竟寫到了文件中還是內核緩沖區中對于進程來說是沒有差別 的,如果進程A和進程B打開同一文件,進程A寫到內核I/O緩沖區中的數據從進程B也能讀到,因為內核空間是進程共享的,
而c標準庫的I/O緩沖區則不具有這一特性,因為進程的用戶空間是完全獨立的.(個人覺得這句話非常重要)

不帶緩存的read和write是相對于 fread/fwrite等流函數來說明的,因為fread和fwrite是用戶函數(3),所以他們會在用戶層進行一次數據的緩存,而read/write是系統調用(2)所以他們在用戶層是沒有緩存的,所以稱read和write是無緩存的IO,其實對于內核來說還是進行了緩存,不過用戶層看不到罷了。

上面的內容介紹了庫緩沖機制,其中也提到了內核緩沖區這個概念,到底內核緩沖存在的價值是很么呢:

為什么總是需要將數據由內核緩沖區換到用戶緩沖區或者相反呢?

答:用戶進程是運行在用戶空間的,不能直接操作內核緩沖區的數據。 用戶進程進行系統調用的時候,會由用戶態切換到內核態,待內核處理完之后再返回用戶態

應用緩沖技術能很明顯的提高系統效率。內核與外圍設備的數據交換,內核與用戶空間的數據交換都是比較費時的,使用緩沖區就是為了優化這些費時的操作。其實核心到用戶空間的操作本身是不buffer的,是由I/O庫用buffer來優化了這個操作。比如read本來從內核讀取數據時是比較費時的,所以一次取出一塊,以避免多次陷入內核。

應用內核緩沖區的 主要思想就是一次讀入大量的數據放在緩沖區,需要的時候從緩沖區取得數據。

管理員模式和用戶模式之間的切換需要消耗時間,但相比之下,磁盤的I/O操作消耗的時間更多,為了提高效率,內核也使用緩沖區技術來提高對磁盤的訪問速度。磁盤是數據塊 的集合,內核會對磁盤上的數據塊做緩沖。內核將磁盤上的數據塊復制到內核緩沖區中,當一個用戶空間中的進程要從磁盤上讀數據時,內核一般不直接讀磁盤,而 是將內核緩沖區中的數據復制到進程的緩沖區中。當進程所要求的數據塊不在內核緩沖區時,內核會把相應的數據塊加入到請求隊列,然后把該進程掛起,接著為其 他進程服務。一段時間之后(其實很短的時間),內核把相應的數據塊從磁盤讀到內核緩沖區,然后再把數據復制到進程的緩沖區中,最后喚醒被掛起的進程。

注:理解內核緩沖區技術的原理有助于更好的掌握系統調用read&write,read把數據從內核緩沖區復制到進程緩沖區,write把數據從進程緩沖區復制到內核緩沖區,它們不等價于數據在內核緩沖區和磁盤之間的交換。

從理論上講,內核可以在任何時候寫磁盤,但并不是所有的write操作都會導致內核的寫動作。內核會把要寫的數據暫時存在緩沖區中,積累到一定數量后再一 次寫入。有時會導致意外情況,比如斷電,內核還來不及把內核緩沖區中的數據寫道磁盤上,這些更新的數據就會丟失。

應用內核緩沖技術導致的結果是:提高了磁盤的I/O效率;優化了磁盤的寫操作;需要及時的將緩沖數據寫到磁盤。

以上這篇淺談帶緩沖I/O 和不帶緩沖I/O的區別與聯系就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持億速云。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

东丽区| 泗水县| 黑龙江省| 宜兴市| 蓝山县| 澄城县| 隆德县| 西华县| 出国| 临安市| 蓝山县| 海兴县| 定日县| 红桥区| 定襄县| 年辖:市辖区| 博客| 大英县| 湄潭县| 牙克石市| 大安市| 德保县| 修文县| 长顺县| 和平县| 舞阳县| 屏南县| 安吉县| 化隆| 台湾省| 兴业县| 灯塔市| 台东县| 南漳县| 永济市| 永平县| 邵东县| 壤塘县| 桃园市| 天长市| 梓潼县|