一、概念理解
linux中IO的類型分為四類:同步(sync)和異步(async),阻塞(block)和非阻塞(unblock)
同步:發出一個功能調用時,在沒有得到結果前會一直等待,直到返回結果。
異步:當異步過程調用發出后,調用者不能立刻得到結果。在完成后,通過通知機制或回調函數來通知調用者
阻塞:調用結果返回前,當前線程會被掛起(線程進入非可執行狀態,在這個狀態下,CPU不會給線程分配時間片,即線程暫停運行)。函數只有在得到結果后才返回
注意:同步和阻塞是不同的,對同步調用,線程是激活的,當調用者等待的時候,線程還可以處理其它請求,而阻塞線程是會掛起的,是不會處理其它請求的。
非阻塞:在結果返回前,函數不會阻塞當前線程,而會立刻返回
同步IO和異步IP的區別在于:數據拷貝的時候進程是否阻塞。
阻塞IO和非阻塞IO的區別在于:應用程序的調用是否立即返回
二、linux下的五種I/O模型
1、阻塞I/O (blocking I/O)
2、非阻塞I/O (nonblocking I/O)
3、I/O 復用 (I/O multiplexing)
4、信號驅動I/O (signal driven I/O (SIGIO))
5、異步I/O (asynchronous I/O)
前四種都是同步,只有最后一種才是異步IO
阻塞IO模型:
進程會一直阻塞,直到數據拷貝完成
應用程序調用一個IO函數,導致應用程序阻塞,等待數據準備好。數據準備好后,從內核拷貝到用戶空間,IO函數返回成功指示。阻塞IO模型圖如下所示:
非阻塞IO模型
通過進程反復調用IO函數,在數據拷貝過程中,進程是阻塞的。模型圖如下所示
IO復用模型
主要是select和epoll,對一個IO端口,兩次調用,兩次返回,關鍵能實現同時對多個IO端口進行監聽。模型如下所示
信號驅動IO
兩次調用,再次返回
首先我們允許套接口進行信號驅動IO,并安裝一個信號處理函數,進程繼續運行并不阻塞。當數據準備好時,進程會收到一個SIGIO信號,可以在信號處理函數中調用IO函數處理數據,模型如下所示
異步IO模型
數據拷貝時進程無阻塞,模型如下所示
5個IO模型的比較
如果這種模型難以理解,筆者利用去飯館吃面做解釋,有不符合的地方請諒解:
blocking IO:去飯館點過面后,一直要在飯館等待面做好
nonblocking IO:去飯館點過面后,可以出去,但不知道什么時間面才好,要過1分鐘來看下,處于忙等待,其它什么事也做不了。
multiplexing IO:這里相當于飯館加了一個服務員,去飯館點面不用知會老板,而是知會服務員,知會后在店里等待服務員通知面做好,在等待這段時間內,服務員也可以招待其它人員。服務員通知面做好了,自己把面端過來
signal-driven IO:在飯館點過面后,可以出去,等面做好了,老板會打電話通知,但是面還是要自己端過來
asynchronous IO:去飯館點過面后,可以出去,出去前指定自己坐哪個位置,等面做好了,老板會把面端到你指定的位置,再打電話通知你
三、select、poll、epoll簡介
epoll是linux所特有,而select是POSIX所規定,一般操作系統均有實現。
select:查找
select本質是通過設置或檢查存放fd標志位的數據結構來進行下一步處理。缺點是:
1、單個進程可監視的fd數量被限制,即能監聽端口的大小有限。
一般來說和系統內存有關,具體數目可以cat /proc/sys/fs/file-max察看。32位默認是1024個,64位默認為2048個
2、對socket進行掃描時是線性掃描,即采用輪詢方法,效率低。
當套接字比較多的時候,每次select()都要遍歷FD_SETSIZE個socket來完成調度,不管socket是否活躍都遍歷一遍。會浪費很多CPU時間。如果能給套接字注冊某個回調函數,當他們活躍時,自動完成相關操作,就避免了輪詢,這正是epoll與kqueue做的
3、需要維護一個用來存放大量fd的數據結構,會使得用戶空間和內核空間在傳遞該結構時復制開銷大
poll:
poll本質和select相同,將用戶傳入的數據拷貝到內核空間,然后查詢每個fd對應的設備狀態,如果設備就緒則在設備等待隊列中加入一項并繼續遍歷,如果遍歷所有fd后沒有發現就緒設備,則掛起當前進程,直到設備就緒或主動超時,被喚醒后又要再次遍歷fd
它沒有最大連接數的限制,原因是它是基于鏈表來存儲的,但缺點是:
1、大量的fd的數組被整體復制到用戶態和內核空間之間,不管有無意義。
2、poll還有一個特點“水平觸發”,如果報告了fd后,沒有被處理,那么下次poll時再次報告該ffd。
epoll:
epoll支持水平觸發和邊緣觸發,最大特點在于邊緣觸發,只告訴哪些fd剛剛變為就緒態,并且只通知一次。還有一特點是,epoll使用“事件”的就緒通知方式,通過epoll_ctl注冊fd,一量該fd就緒,內核就會采用類似callback的回調機制來激活該fd,epoll_wait便可以收到通知。
epoll的優點:
1、沒有最大并發連接的限制
2、效率提升,只有活躍可用的FD才會調用callback函數
3、內存拷貝,利用mmap()文件映射內存加速與內核空間的消息傳遞。
select、poll、epoll區別總結:
1、支持一個進程打開連接數
select:32位機器1024個,64位2048個
poll:無限制,原因基于鏈表存儲
epoll:有上限,但很大,2G內存20W左右
2、IO效率
select:IO效率低
poll:IO效率低
epoll:只有活躍的socket才調用callback,IO效率高。
3、消息傳遞方式
select:內核需要將消息傳遞到用戶空間,都需要內核拷貝動作
poll:同上
epoll:通過內核與用戶空間共享一塊內存來實現。
本文系轉載文章,感謝原作者的辛勤付出!
來源:http://linuxkingdom.blog.51cto.com/6334977/1654813