I/O在計算機中指Input/Output, IOPS (Input/Output Per Second)即每秒的輸入輸出量(或讀寫次數),是衡量磁盤性能的主要指標之一。IOPS是指單位時間內系統能處理的I/O請求數量,通常以每秒處理的I/O請求數量爲單位,I/O請求一般爲讀或寫數據操做請求。 linux
一次完整的I/O是用戶空間的進程數據與內核空間的內核數據的報文的完整交換,可是因爲內核空間與用戶空間是嚴格隔離的,因此其數據交換過程當中不能由用戶空間的進程直接調用內核空間的內存數據,而是須要經歷一次從內核空間中的內存數據copy到用戶空間的進程內存當中,因此簡單說I/O就是把數據從內核空間中的內存數據複製到用戶空間中進程的內存當中。
而網絡通訊就是網絡協議棧到用戶空間進程的IO就是網絡IO nginx
磁盤I/O是進程向內核發起系統調用,請求磁盤上的某個資源好比是文件或者是圖片,而後內核經過相應的驅動程序將目標圖片加載到內核的內存空間,加載完成以後把數據從內核內存再複製給進程內存,若是是比較大的數據也須要等待時間。 apache
每次IO,都要經由兩個階段:windows
同步/異步:關注的是消息通訊機制,即在等待一件事情的處理結果以前,被調用者是否提供通知機制。
同步:進程發出請求調用後,等待內核返回響應以後再進行下一個請求。若是內核不進行返回數據,則進程一直處於等待狀態。
異步:進程發出請求調用後,不等待內核返回響應,直接處理下一個請求。(Nginx是異步處理機制)服務器
阻塞/非阻塞:關注調用者在等待結果返回以前所處的狀態。
阻塞:I/O操做須要完全完成以後才返回到用戶空間,操做返回以前,調用者處於被掛起狀態,沒法執行其餘操做。
非阻塞:I/O操做被調用後當即返回給用戶一個狀態值,無需等待完成,最終的調用結果返回以前,調用者不會被掛起,能夠執行其餘操做。網絡
阻塞IO模型是最簡單的IO模型,用戶線程在內核進行IO操做時被阻塞 用戶線程經過系統調用read發起IO讀操做,由用戶空間轉到內核空間。內核等到數據包到達後,而後將接收的數據拷貝到用戶空間,完成read操做 用戶須要等待read將數據讀取到buffer後,才繼續處理接收的數據。整個IO請求的過程當中,用戶線程是被阻塞的,這致使用戶在發起IO請求時,不能作任何事情,對CPU的資源利用率不夠 優勢:程序簡單,在阻塞等待數據期間進程/線程掛起,基本不會佔用 CPU 資源 缺點:每一個鏈接須要獨立的進程/線程單獨處理,當併發請求量大時爲了維護程序,內存、線程切換開銷較大,apache 的preforck使用的是這種模式。併發
簡單理解就是:程序向內核發送I/O請求後一直處於等待內核響應的狀態,若是內核處理請求的I/O操做不能當即返回,則進程將一直處於等待狀態而再也不接收新的請求,並由進程輪詢查看I/O是否完成,完成後進程將I/O結果返回給Client,在I/O沒有返回期間進程不能接收其餘客戶的請求,並且是由進程本身去看I/O是否完成,這種方式簡單,可是比較慢,因此用的比較少。異步
用戶線程發起IO請求時當即返回。但並未讀取到任何數據,用戶線程須要不斷地發起IO請求,直到數據到達後,才真正讀取到數據,繼續執行。即 「輪詢」機制存在兩個問題:若是有大量文件描述符都要等,那麼就得一個一個的read。這會帶來大量的Context Switch(read是系統調用,每調用一次就得在用戶態和核心態切換一次)。輪詢的時間很差把握。這裏是要猜多久以後數據才能到。等待時間設的太長,程序響應延遲就過大;設的過短,就會形成過於頻繁的重試,乾耗CPU而已,是比較浪費CPU的方式,通常不多直接使用這種模型,而是在其餘IO模型中使用非阻塞IO這一特性。socket
簡單理解就是:程序向內核發送I/O請求後一直等待內核響應,若是內核處理請求的I/O操做不能理解返回I/O結果,進程將再也不等待,繼續處理其餘請求,可是仍然須要進程每隔一段時間就要查看內核I/O是否完成。這是一種比較浪費CPU的一種方式:輪詢的時間很差把握,若是設置的等待時間過長,程序響應延遲就過大;設置的時間太短,就會形成過於頻繁的重試。async
I/O多路複用型就是咱們說的select,poll,epoll,有些地方也稱這種IO方式爲event driven IO。select/epoll的好處就在於單個process就能夠同時處理多個網絡鏈接的IO。它的基本原理就是select,poll,epoll這個function會不斷的輪詢所負責的全部socket,當某個socket有數據到達了,就通知用戶進程。 當用戶進程調用了select,那麼整個進程會被block,而同時,kernel會「監視」全部select負責的socket,當任何一個socket中的數據準備好了,select就會返回。這個時候用戶進程再調用read操做,將數據從kernel拷貝到用戶進程。好比:Apache prefork是此模式的select,work是poll模式。
簡單理解即:I/O多路複用機制能夠同時監控多個描述符,當某個描述符就緒(讀或者寫就緒),則當即通知相應程序進行讀或者寫操做。但select、poll、epoll本質上都是同步I/O,由於他們都須要在讀寫事件就緒後本身負責進行讀寫,也就是說這個讀寫過程是阻塞的。
信號驅動IO就是用戶進程能夠經過sigaction系統調用註冊一個信號處理程序,而後主程序能夠繼續向下執行,當有IO操做準備就緒時,由內核通知觸發一個SIGIO信號處理程序執行,而後將用戶進程所須要的數據從內核空間拷貝到用戶空間 此模型的優點在於等待數據報到達期間進程不被阻塞。用戶主程序能夠繼續執行,只要等待來自信號處理函數的通知。
優勢:線程並無在等待數據時被阻塞,內核直接返回調用接收信號,不影響進程繼續處理其餘請求所以能夠提升資源的利用率
簡單理解就是:程序進程經過在內核上調用sigaction函數,向內核發送I/O調用後,不用等待內核響應,能夠繼續接受其餘請求,內核收到進程請求後進行的I/O若是不能當即返回,就由內核等待結果,直到I/O完成後內核再通知進程。apache event就是這個模式。
相對於同步IO,異步IO不是順序執行。用戶進程進行aio_read系統調用以後,不管內核數據是否準備好,都會直接返回給用戶進程,而後用戶態進程能夠去作別的事情。等到socket數據準備好了,內核直接複製數據給進程,而後從內核向進程發送通知。IO兩個階段,進程都是非阻塞的。 Linux提供了AIO庫函數實現異步,可是用的不多。目前有不少開源的異步IO庫,例如libevent、libev、libuv。
程序進程向內核發送IO調用後,不用等待內核響應,能夠繼續接受其餘強求,內核調用的IO若是不能當即返回,內核會繼續處理其餘事物,知道IO完成後將結果通知給內核,內核再將IO完成的結果返回給進程,期間進程能夠接受新的請求,內核也能夠處理新的事物,所以相互之間是不影響的。能夠實現較大的同時並實現較高的IO複用,所以異步非阻塞是使用最多的一種通訊方式。
Nginx支持在多種不一樣的操做系統實現不一樣的事件驅動模型,可是其在不一樣的操做系統甚至是不一樣的系統版本上面的實現方式不盡相同,主要有如下實現方式