深刻淺出IO模型

什麼是IO?

在類unix系統中,全部的IO設備(網絡,磁盤,終端...)都被模型化爲文件,IO是主存(main memory)和外部設備(磁盤,終端,網絡...)之間拷貝數據的過程。node

I/O的過程

  • 打開文件

應用進程請求內核打開文件,內核返回一個文件的描述符(非負整數),內核記錄打開的文件的全部信息,應用進程只需記錄文件描述符。linux

  • 改變當前文件的位置

內核中記錄一個文件位置k,每一個打開的文件初始爲0,應用進程能夠經過seek操做,顯式的改變文件的位置。c++

  • 讀寫文件

讀:從文件位置k開始讀取n個字節到存儲器,而後將k增長到k+n。編程

寫:存儲器拷貝從k開始,n結束個字節到一個文件,而後更新k。緩存

  • 關閉文件

應用進程請求內核關閉文件,內核釋放記錄的文件信息,將文件描述符釋放回描述符池。網絡

IO模型

咱們想要了解操做系統的IO模型須要先了解幾個基本的概念。併發

  • 阻塞:請求不能當即獲得應答,須要等待。異步

  • 非阻塞:請求當即獲得應答,不須要等待。函數

  • 同步I/O:同步I/O操做引發請求進程阻塞,直到I/O操做完成。性能

  • 異步I/O:異步I/O操做不引發請求進程阻塞。

舉個🌰

在🌰中咱們的請求進程化身肥宅,操做系統內核化身外賣老闆。

場景是肥宅週末早上在家餓了,想要吃外賣。

下面是肥宅叫外賣不一樣的方式。

阻塞:肥宅打了外賣的電話,外賣的老闆正在忙,因此把肥宅掛着,肥宅只能等老闆忙完才能訂外賣。

非阻塞:肥宅打了外賣的電話,無論有沒有東西賣給肥宅,外賣老闆都當即回覆了肥宅。

同步I/O:肥宅打了外賣的電話,外賣老闆告訴肥宅外賣何時送到,肥宅須要本身定時打電話問一下外賣到了沒。

異步I/O:肥宅打了外賣的電話下了訂單,肥宅就去打遊戲去了。外賣老闆會在指定的時間把外賣送到肥宅家裏,並打電話讓肥宅來取。

五種I/O模型

瞭解了阻塞,非阻塞,異步與同步,下面咱們的五種I/O模型都會用到這些概念。

阻塞I/O模型

阻塞I/O模型

請求進程發起系統調用後,一直等待內核數據拷貝完成,整個過程請求進程是阻塞的。

非阻塞I/O模型

非阻塞I/O模型

請求進程發起系統調用後,若是內核沒有準備好會返回一個EWOULDBLOCK。而後請求進程會一直輪詢內核,直到內核準備好,開始拷貝數據。

I/O複用模型

I/O複用模型

  • select: 多個的進程的IO能夠註冊到一個複用器(select)上,而後用一個進程調用該select, select會監聽全部註冊進來的IO。單個進程所能打開的文件描述符最大隻能是1024。使用該技術會有C10K併發問題
  • poll: 對select的一種優化,基於鏈表實現,沒有了1024的限制,可是對鏈表的遍歷使性能低下。
  • epoll: 不須要線性遍歷,經過callback進行IO完成後的通知。(因爲AIO不成熟,在linux大多使用epoll)
  • kqueue: 與epoll相似,存在FreeBSD中。

信號驅動I/O模型

信號驅動I/O模型

當進程發起一個IO操做,會向內核註冊一個信號處理函數,而後進程返回不阻塞;當內核數據就緒時會發送一個信號給進程,進程便在信號處理函數中調用IO讀取數據。

異步I/O模型

異步I/O

當進程發起一個IO操做,進程返回(不阻塞),但也不能返回結果;內核把整個IO處理完後,會通知進程結果。若是IO操做成功則進程直接獲取到數據。

I/O模型的比較

I/O模型的比較

同步阻塞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上),線程間經過信號量進行通訊。

異步I/O庫

  • glibc aio: 缺陷是自帶單獨的執行線程去執行回調函數,這對使用者來講很難控制。
  • ACE:ACE 過於複雜,甚至比它試圖封裝的對象更復雜。
  • libevent : 名氣最大,應用最普遍,歷史悠久的跨平臺事件庫。(缺點:使用全局變量,定時器沒法處理時間跳變等設計缺陷。)
  • libev : 較libevent而言,設計更簡練,性能更好。(缺點:對Windows支持不夠好)
  • libuv : 開發node的過程當中須要一個跨平臺的事件庫,他們首選了libev,但又要支持Windows,故從新封裝了一套,*nix下早期用libev實現(現已本身實現),Windows下用IOCP實現;(缺點:沒有正確的處理 TCP 關閉,容許空回調,用戶不知道出錯在哪裏)。
  • ASIO:在epoll的基礎上用iocp的思想墊了一層,而後封裝爲統一接口(缺點:在linux上會損失一部分效率)。

Libevent、libev、libuv三個網絡庫,都是c語言實現的異步事件庫Asynchronousevent library)。

ASIO在2017年進入了c++標準。

node的異步I/O底層庫使用的是libuv。

參考連接

unix網絡編程

那些年咱們追過的網絡庫

相關文章
相關標籤/搜索