1.阻塞io,linux下默認所有的io都是阻塞的,
當發(fā)起io操作時,程序阻塞,直到io完成才會返回。浪費cpu的資源。
2非阻塞io
當發(fā)起io操作后,程序會立即返回,之后程序不斷輪詢,判斷io是否就緒。這種情況下的輪訓就是傻輪詢,無論io是否就緒,會一直去問。但是好的一點是,在while的輪詢過程中可以做一些其它的事情。但是這種非阻塞io往往需要配合多線程達到高效率。因為服務器往往有多個客戶端的連接,單一線程要實現(xiàn)對多個連接的管理,往往需要通過隊列,對多個socket進行管理,這對用戶來說往往很困難(有幾個人能手寫linux內(nèi)核對select或epoll的底層實現(xiàn)?),而多線程的切換又是十分消耗系統(tǒng)資源的,所以非阻塞io+多線程實現(xiàn)高性能服務器,往往效果也不是很好。
3.io多路復用(select/epoll)(reactor)
多線程是十分耗費系統(tǒng)資源的,那么我們自然而然就想到能否用單線程實現(xiàn)對多個客戶端socket的管理,在上面提到如果在用戶態(tài)完成這個任務是比較困難的,但是慶幸的是linux內(nèi)核幫我們實現(xiàn)了這個復雜的操作,典型的兩種是select和epoll.二者的區(qū)別
select
用一個eventloop隊列去管理多個socket,沒有io時,select阻塞掛起,但是它只知道有數(shù)據(jù)到達,并不知道是那個fd(socket)的,所以需要遍歷所有的fd,找出真正被觸發(fā)的socket,執(zhí)行其對應的處理函數(shù)。
epoll
epoll同樣維護了一個輪詢的eventloop,但是不同的是它在客戶端有數(shù)據(jù)到達時,會被顯示的告知是哪幾個socket被觸發(fā),因此不需要再用o(n)的時間復雜度去輪詢,所以性能很高。epoll是單線程異步io,但是這種異步并不是那么純,因為數(shù)據(jù)。
4.信號驅(qū)動
不常用
5.異步io(被動告知異步)
沒有阻塞,就是當數(shù)據(jù)到達時,利用中斷機制切換到用戶態(tài)處理。io多路復用需要主動輪詢,用戶自己將數(shù)據(jù)從內(nèi)核態(tài)地址空間拷貝到用戶態(tài),而異步io會將數(shù)據(jù)的同步自動完成,用戶進程只需要去讀取數(shù)據(jù)即可。
異步io和io多路復用區(qū)別是異步io是事情做完了你通知我一聲,而io多路復用是事情可以做的話你告訴我一聲,我去做。
io多路復用會阻塞用戶socket,而異步io不會阻塞用戶線程。
io多路復用是同步io,因為用戶態(tài)還要去輪詢看看哪些事件可以就緒執(zhí)行,(雖然操作系統(tǒng)已經(jīng)觸發(fā)了對應事件,但是用戶還得去輪詢隊列中一遍遍查看)
異步io(異步非阻塞)用戶進程不會被阻塞。
阻塞:調(diào)用立即返回
非阻塞:調(diào)用不返回
同步: 我自己去問消息是否完成。
異步:主動告知我消息是否完成。