程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 淺談帶緩沖I/O 和不帶緩沖I/O的區別與聯絡

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

編輯:關於C++

淺談帶緩沖I/O 和不帶緩沖I/O的區別與聯絡。本站提示廣大學習愛好者:(淺談帶緩沖I/O 和不帶緩沖I/O的區別與聯絡)文章只能為提供參考,不一定能成為您想要的結果。以下是淺談帶緩沖I/O 和不帶緩沖I/O的區別與聯絡正文


這裡搜集從網上看到的一些言論,自以為還是比擬靠譜的,有些不靠譜的依據自己的了解停止了修正。

首先要明白不帶緩沖的概念:所謂不帶緩沖,並不是指內核不提供緩沖,而是只單純的零碎調用,不是函數庫的調用。零碎內核對磁盤的讀寫都會提供一個塊緩沖(在有些中央也被稱為內核高速緩存),當用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的區別與聯絡就是分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved