下表列出了緩衝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... |
在闡述兩者的原理對比以前,先解釋幾個關鍵概念:網絡
對於緩衝I/O,每一個讀寫操做會有3次數據拷貝。例如讀:磁盤->內核緩衝區->用戶緩衝區->應用程序內存。
對於直接I/O,每一個讀寫操做會有2次數據拷貝,跳過了用戶級的緩衝。多線程
關於緩衝I/O和直接I/O,有幾點須要特別說明:併發
用戶空間不分配物理內存,直接將應用程序的邏輯內存地址映射到Linux操做系統的內核緩衝區,應用程序讀寫的時候實際讀寫的是內核緩衝區。此時數據的拷貝次數減小爲了1次。socket
當用戶須要把文件中的數據發送到網絡的時候,使用直接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);