在類unix系統中,全部的IO設備(網絡,磁盤,終端...)都被模型化爲文件,IO是主存(main memory)和外部設備(磁盤,終端,網絡...)之間拷貝數據的過程。node
應用進程請求內核打開文件,內核返回一個文件的描述符(非負整數),內核記錄打開的文件的全部信息,應用進程只需記錄文件描述符。linux
內核中記錄一個文件位置k,每一個打開的文件初始爲0,應用進程能夠經過seek操做,顯式的改變文件的位置。c++
讀:從文件位置k開始讀取n個字節到存儲器,而後將k增長到k+n。編程
寫:存儲器拷貝從k開始,n結束個字節到一個文件,而後更新k。緩存
應用進程請求內核關閉文件,內核釋放記錄的文件信息,將文件描述符釋放回描述符池。網絡
咱們想要了解操做系統的IO模型須要先了解幾個基本的概念。併發
阻塞:請求不能當即獲得應答,須要等待。異步
非阻塞:請求當即獲得應答,不須要等待。函數
同步I/O:同步I/O操做引發請求進程阻塞,直到I/O操做完成。性能
異步I/O:異步I/O操做不引發請求進程阻塞。
在🌰中咱們的請求進程化身肥宅,操做系統內核化身外賣老闆。
場景是肥宅週末早上在家餓了,想要吃外賣。
下面是肥宅叫外賣不一樣的方式。
阻塞:肥宅打了外賣的電話,外賣的老闆正在忙,因此把肥宅掛着,肥宅只能等老闆忙完才能訂外賣。
非阻塞:肥宅打了外賣的電話,無論有沒有東西賣給肥宅,外賣老闆都當即回覆了肥宅。
同步I/O:肥宅打了外賣的電話,外賣老闆告訴肥宅外賣何時送到,肥宅須要本身定時打電話問一下外賣到了沒。
異步I/O:肥宅打了外賣的電話下了訂單,肥宅就去打遊戲去了。外賣老闆會在指定的時間把外賣送到肥宅家裏,並打電話讓肥宅來取。
瞭解了阻塞,非阻塞,異步與同步,下面咱們的五種I/O模型都會用到這些概念。
請求進程發起系統調用後,一直等待內核數據拷貝完成,整個過程請求進程是阻塞的。
請求進程發起系統調用後,若是內核沒有準備好會返回一個EWOULDBLOCK。而後請求進程會一直輪詢內核,直到內核準備好,開始拷貝數據。
當進程發起一個IO操做,會向內核註冊一個信號處理函數,而後進程返回不阻塞;當內核數據就緒時會發送一個信號給進程,進程便在信號處理函數中調用IO讀取數據。
當進程發起一個IO操做,進程返回(不阻塞),但也不能返回結果;內核把整個IO處理完後,會通知進程結果。若是IO操做成功則進程直接獲取到數據。
同步阻塞IO、同步非阻塞IO、IO多路複用、信號驅動IO都屬於同步IO。
只有異步IO屬於異步IO。
linux異步I/O有基於線程池的,但AIO有缺陷(沒法利用系統緩存等),使用比較多的是epoll。(AIO是posix標準)
win異步I/O使用比較多的是IOCP。
異步I/O線程池主流的實現是IO線程負責I/O(大部分時間阻塞在I/O上),線程間經過信號量進行通訊。
Libevent、libev、libuv三個網絡庫,都是c語言實現的異步事件庫Asynchronousevent library)。
ASIO在2017年進入了c++標準。
node的異步I/O底層庫使用的是libuv。