對於開發者開說,i/o是繞不過的話題。從檔案i/o到網路i/o,存在著各種各樣的概念和模型,今天來聊聊檔案i/o。
型別對應api
緩衝i/o
fopen,fclose,fseek,fflush,fead,fwrite,fprintf,fscanf……
直接i/o
open,close,lseek,fsync,read,write,pread,pwrite……
在講檔案i/o之前先弄清楚幾個概念:
應用程式記憶體:是通常寫**用malloc/free、new/delete登分配出來的記憶體。
使用者緩衝區:c語言中的file結構體裡面的buffer。file結構體的定義如下,可以看到裡面有定義的buffer;
typedef strust
file;
核心緩衝區:linux作業系統的page cache 。為了加快磁碟的i/o,linux系統會把磁碟上的資料以page為單位快取在作業系統的記憶體裡,這裡的page是linux系統定義的乙個邏輯概念,乙個page一般是4k。
對於快取i/o,乙個讀操作會有3次資料拷貝,乙個寫操作也有3次資料拷貝。
讀:磁碟–>核心緩衝區–>使用者緩衝區–>應用程式記憶體;
寫:應用程式記憶體–>使用者緩衝區–>核心緩衝區–>磁碟。
對於直接i/o,乙個讀操作會有2次資料拷貝,乙個寫操作,也有2次資料拷貝;
讀:磁碟–>核心緩衝區–>應用程式記憶體;
寫:應用程式記憶體–>核心緩衝區–>磁碟。
記憶體對映檔案
相比於直接i/o,記憶體對映檔案往前更進了一步。當使用者空間不再用物理記憶體,直接拿應用程式的邏輯記憶體位址對映到linux作業系統的核心緩衝區,應用程式雖然讀寫的是自己的記憶體,但這個記憶體只是乙個「邏輯位址」,實際讀寫的是核心緩衝區。
資料拷貝次數從緩衝i/o的3次,到直接i/o的2次,再到記憶體對映檔案,變成1次。
讀:磁碟–>核心緩衝區;
寫:核心緩衝區–>磁碟。
在linux系統中,記憶體對映檔案的的系統api:
void* mmap(void* start,size_t length,int port,int flags,int fd, off_t orrset);
當使用者需要把檔案中的資料傳送到網路的時候,如果不用零拷貝,實現方式:
實現方式(1):直接i/o 方式,偽**如下:
fd1=開啟的檔案描述符
fd2=開啟的socket描述符
buffer=應用程式記憶體
read(fd1,buffer...); //先把資料從檔案中讀出來
write(fd2,buffer...); //再通過網路發出去
如圖所示:整個過程會有4次資料拷貝,讀2次,寫2次;
實現方式(2):記憶體對映方式,偽**如下:
fd1=開啟的檔案描述符
fd2=開啟的socket描述符
buffer=應用程式記憶體
mmap(fd1,buffer...); //先把磁碟資料對映到buffer上
write(fd2,buffer...); //再通過網路發出去
如圖所示:整個過程有3次資料拷貝,不再經過應用程式記憶體,直接在核心空間中,從核心緩衝區拷貝到socket緩衝區。
零拷貝
零拷貝是提公升i/o效率的又一利器,kafka中在消費訊息的時候就是利用了零拷貝技術。
如圖所示,零拷貝連核心緩衝區到socket緩衝區的拷貝也省了。核心緩衝區和socket緩衝區沒做資料拷貝,只是乙個位址的對映,底層的網絡卡驅動程式要讀取資料併發送到網路的時候,看似讀的是socket緩衝區的資料,但實際上直接讀取是記憶體緩衝區的資料。在這裡,雖然叫零拷貝,實際是有2次資料拷貝,1次是從磁碟到核心緩衝區,1次是從核心緩衝區到socket緩衝區。之所以叫零拷貝,是從記憶體的角度來看的,資料在記憶體中沒有發生資料拷貝,只在記憶體和i/o之間傳輸。
在linux系統中,零拷貝的api為:
sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
最後總結一下:對於把檔案資料傳送到網路的這個場景,直接i/o、記憶體對映檔案、零拷貝對應的資料拷貝次數分別是:4次、3次、2次,記憶體拷貝分別是:2次、1次、0次。 系統io(檔案io)
檔案描述符 檔案描述符 已開啟檔案的標誌,是非負整形數,當前可以最小作為新檔案的檔案描述符,預設範圍0 1024 可更改 檔案開啟 int open const char pathname,int flags,mode t mode 1.pathname 要開啟檔案的路徑 2.flags 開啟方式 ...
IO操作 檔案IO
一 系統呼叫 系統呼叫實際上是作業系統 核心 提供的供使用者使用的介面函式。二 標準io函式和檔案io函式的關係 標準io是c庫內定義的函式,是凌駕於系統之上的,適用於任何的作業系統 檔案io是由linux系統提供的,只能在linux系統中使用,而不可以在其它作業系統中使用。標準io函式可以呼叫檔案...
檔案IO操作
在對乙個檔案或者裝置進行讀寫之前,都需要先開啟,以獲得該檔案或者裝置的操作指標,也就是檔案描述符。有了檔案描述符,後續就可以進行讀取,修改操作了。標頭檔案函式宣告 int open const char pathname,int flags,mode t mode 返回值成功 返回檔案描述符 失敗 ...