天天看點

read/write資料讀寫傳輸方式(轉)

前言

       筆者本打算撰寫一篇講解标準I/O(緩存I/O)的博文,但是發現已經有網友做過同樣的工作,并且工作品質上乘,特轉載于此。

       原文位址http://lenky.info/archives/2012/08/1856     

正文

      利用系統調用函數read()/write()是我們平常用得最多的一種資料讀寫方式,大多數情況下我們并沒有考慮這種資料讀寫方式的執行效率,因為在很多并不以資料頻繁讀寫為性能瓶頸的應用程式中函數read()/write()消耗的執行時間可以忽略,但是它們内在具體實作和執行效率到底如何呢?下面我們就來進行詳細的分析。

函數read()/write()定義在頭檔案unistd.h内,原型如下:

#include <unistd.h>
ssize_t read(int fildes, void *buf, size_t nbyte);
ssize_t write(int fildes, const void *buf, size_t nbyte);      

       在這裡我并不打算講解函數read()/write()的源碼,簡略的描述其執行過程,涉及到的主要調用關系如下圖所示:

read/write資料讀寫傳輸方式(轉)

      如果我們的伺服器程式,比如nginx采用read()/write()資料讀寫傳輸方式,當某用戶端發送“GET /index.htm HTTP/1.1”請求時,nginx則需将存放在站點根目錄的index.htm文本檔案當作響應資料發送給用戶端。當沒有啟用mmap()的情況下,nginx完成這個響應資料的發送工作需要兩步,首先利用函數read()将index.htm文本檔案資料讀入記憶體,接着利用函數write()将第一步讀入記憶體的資料寫到連接配接套接口描述符來完成響應資料的發送:

read/write資料讀寫傳輸方式(轉)

      如上圖所示,nginx應用程式利用read()/write()資料讀寫傳輸方式完成響應資料的發送工作一共需要4次上下文切換和4次資料拷貝(即假定為一次read()/write()就将index.htm文本檔案資料發送完畢的情況,如果不隻一次則切換和拷貝次數将會更多),這些切換和拷貝過程是不是必須的呢?答案是否定的。比如當在啟用mmap()的情況下就可以減少一次資料拷貝,此時利用系統調用mmap()将文本檔案index.htm資料拷貝到核心緩存區,并将拷貝映射目标位址的起始值傳回給nginx應用程式,正是因為nginx應用程式有了這塊核心緩存區的映射起始位址并且可以共享這塊核心緩存區(系統調用mmap()實作的結果),是以在第一幅圖中,從核心Buffer到使用者Buffer再到Socket Buffer的拷貝就可以變成一次從核心Buffer到Socket Buffer的直接拷貝:

read/write資料讀寫傳輸方式(轉)