UNIX下IO模型分析
對UNIX下的五種常見IO模型分析,幫助理解
IO操作的兩個階段
以讀數據操作爲例:
1. 等待內核數據準備(數據拷貝到內核緩衝區)
2. 將數據從內核拷貝到用戶空間
IO模型
UNIX下共有五種常見的IO模型:
下面以recvfrom
接口舉例
阻塞IO
默認情況下,所有的套接字都是阻塞的
調用recvfrom
接口,進程在IO操作的兩個階段都會阻塞,直到最終數據拷貝到用戶空間或者過程中出現錯誤纔會返回,進程在阻塞狀態下是不佔用CPU資源的
最常見的錯誤是發生系統中斷,此時需要重讀,可參考這裏
非阻塞IO
可以通過fcntl(sockfd,F_SETFL,O_NONBLOCK)
將套接字設置成非阻塞
調用recvfrom
接口,無論內核緩衝區是否有可用數據,進程都會立即返回,所以在IO操作的第一階段是非阻塞的; 若無數據可用,內核將errno
設置爲爲EWOULDBLOCK
或者EAGAIN
,進程可以使用輪詢的方法,保證內核在數據準備好時,能立即拷貝到用戶空間; 若有則立即將數據拷貝到用戶空間,進程在數據拷貝到用戶空間即IO操作的第二階段是阻塞的;
非阻塞IO過於消耗CPU時間,將大部分時間用於輪詢
多路複用IO
多路複用系統調用:select
,poll
和epoll
,其中windows平臺不支持poll
和epoll
,使用方法可以參考I/O 多路複用之select、poll、epoll詳解和Linux select/poll和epoll實現機制對比
調用select
,等待內核數據準備,所以IO操作的第一個階段,進程是阻塞的,不過是阻塞在多路複用系統調用上,而不是IO系統調用上; 當select
返回套接字可讀條件時,再調用recvfrom
將數據從內核拷貝到用戶空間,IO操作的第二階段,進程是阻塞的
多路複用IO和阻塞IO,在IO操作的兩個階段都是阻塞的,不過多路複用IO使用了兩個系統調用,而阻塞IO只使用了一個,所以在連接數不是很多的情況下,阻塞IO可能性能更佳; 多路複用IO的優勢在於可以同時監控多個用於IO的文件描述符。
多線程中的阻塞IO,與多路複用IO極爲相似
信號驅動IO
調用sigaction
等系統調用安裝信號處理函數,並立即返回,所以IO操作的第一階段,進程是非阻塞的; 當內核數據準備好時,內核會產生一個信號,通知進程將數據從內核拷貝到用戶空間,IO操作的第二階段,進程是阻塞的
使用方法:IO的多路複用和信號驅動
異步IO
異步IO有一組以aio
開頭的系統調用,使用方法可參考Linux AIO機制
調用異步IO系統調用,給內核傳遞描述字、緩衝區指針、緩衝區大小(與read
相同的三個參數)、文件偏移(與lseek
類似),告訴內核當整個操作完成時如何通知我們,並立即返回,在IO操作的兩個階段,進程都不阻塞
總結
- 同步IO和異步IO的主要區別是將數據從內核拷貝到用戶空間是否阻塞,前者會在將數據從內核拷貝到用戶空間時即IO操作的第二個階段發生阻塞,而後者則在系統調用後直接返回,直到內核發送信號通知IO操作完成,在IO操作的兩個階段都沒有阻塞
- 阻塞IO和非阻塞IO的主要區別是系統調用是否立即返回(默認將數據從內核拷貝到用戶空間即IO操作的第二個階段是立即返回的),前者會在IO操作的兩個階段完成前一直阻塞,後者在內核沒有準備好數據的情況下立即返回,即只會在IO操作的第二個階段阻塞
- 信號驅動IO和異步IO的主要區別在於前者由內核通知我們何時啓動一個IO操作,在將數據從內核拷貝到用戶空間過程中即IO操作的第一個階段依舊是阻塞的,而後者是由內核通知我們IO操作何時完成,在IO操作的兩個階段都沒有阻塞
知乎上有一個比較生動的例子可以說明這幾種模型之間的關係。
Reference
- UNIX網絡編程 卷1:套接字聯網API
- Linux IO模式及 select、poll、epoll詳解
- Linux下5種IO模型的小結
- UNIX網絡編程讀書筆記:I/O模型(阻塞、非阻塞、I/O複用、信號驅動、異步)
- IO - 同步,異步,阻塞,非阻塞 (亡羊補牢篇)
- Linux五種IO模型性能分析
About me
- GitHub:AnSwErYWJ
- Blog:http://www.answerywj.com
- Email:[email protected]
- Weibo:@AnSwEr不是答案
- CSDN:AnSwEr不是答案的專欄
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
本作品採用知識共享署名-相同方式共享 4.0 國際許可協議進行許可。