【架構—基本功】操做系統

緩衝I/O和直接I/O

下表列出了緩衝I/O和直接I/O的API接口列表,緩衝I/O是C語言提供的庫函數,均以f打頭;直接I/O是Linux的系統API,也是C語言編寫的,但在原理上二者差別很大。緩存

類型 對應API接口
緩衝I/O fopen,fclose,fseek,fflush,fread,fwrite,fprintf,fscanf...
直接I/O open,close,lseek,fsync,read,write,pread,pwrite...

在闡述兩者的原理對比以前,先解釋幾個關鍵概念:網絡

  • 應用程序內存:是一般寫代碼用malloc、new等分配出來的內存。
  • 用戶緩衝區:C語言的FILE結構體裏面的buffer。
  • 內核緩衝區:Linux操做系統的Page Cache。爲了加快磁盤的I/O,Linux系統會把磁盤上的數據以Page爲單位緩存在操做系統的內存裏。

對於緩衝I/O,每一個讀寫操做會有3次數據拷貝。例如讀:磁盤->內核緩衝區->用戶緩衝區->應用程序內存。
對於直接I/O,每一個讀寫操做會有2次數據拷貝,跳過了用戶級的緩衝。多線程

關於緩衝I/O和直接I/O,有幾點須要特別說明:併發

  • fflush和fsync的區別。fflush只是把數據從用戶緩衝區刷到內核緩衝區而已,fsync則是把數據從內核緩衝刷到磁盤裏。這意味着不管緩衝I/O,仍是直接I/O,若是在寫數據以後不調用fsync,此時系統斷點重啓,最新的部分數據會丟失。
  • 對於直接I/O,也有read/write和pread/pwrite兩組不一樣的API。pread/pwrite在多線程讀寫同一個文件時頗有用。

內存映射文件與零拷貝

1.內存映射文件

用戶空間不分配物理內存,直接將應用程序的邏輯內存地址映射到Linux操做系統的內核緩衝區,應用程序讀寫的時候實際讀寫的是內核緩衝區。此時數據的拷貝次數減小爲了1次。socket

2.零拷貝

當用戶須要把文件中的數據發送到網絡的時候,使用直接I/O的話會有4次數據拷貝,讀進來2次,寫回去2次。使用內存映射文件的話會有3次數據拷貝,再也不通過用戶程序內存,直接在內核空間中從內核緩衝區拷貝到socket緩衝區。
但若是使用零拷貝,在內核緩衝區和socket緩衝區之間不會使用數據拷貝,只是一個地址的映射,底層的網卡驅動程序要讀取數據併發送到網絡的時候,看似讀的是socket緩衝區的數據,實際上直接讀的是內核緩衝區中的數據。
在Linux系統中,零拷貝的系統API爲:函數

#include<sys/sendfile.h>
ssize_t senfile(int out_fd, int in_fd, off_t *offset, size_t count);

網絡I/O模型

相關文章
相關標籤/搜索