JAVA - IO模型
本章內容
1 同步,異步,阻塞,非阻塞的概念
2 五種IO模型:阻塞式IO,非阻塞式IO,多路復用IO,信號驅動IO,異步IO 各自的特點
同步,異步,阻塞,非阻塞(註意:這裏是從用戶線程和內核層面來介紹概念的)
同步和異步(描述的是用戶線程與內核的交互方式 - 消息的通信機制)
1 同步 用戶線程發起IO後需要等待
2 異步 用戶線程發起IO請求後仍然繼續執行,當內核操作完成後會通知用戶線程,或者調用用戶線程註冊的回調函數
阻塞和非阻塞(描述的是程序等待調用結果是的狀態 - 調用者的狀態)
1 阻塞 在調用結果返回之前,調用者的執行線程會掛起,線程不能做其它事情,只有等待結果返回才能往下執行
2 非阻塞 IO操作被調用後立即返回調用者一個狀態值,無需等待IO操作徹底完成
IO模型
介紹
操作系統為了安全,將內存空間分成了用戶空間和內核空間,用戶進程無法直接操作底層硬件,只能將請求提交給CPU,由CPU去執行
進程(線程)將請求提交給CPU,等待CPU返回數據(這是一個兩段式的過程)
1 等待數據準備:內核從IO設備將數據拷至內存空間的Buffer中
2 內核將數據從內部的Buffer中拷貝至進程空間
註意:內核在IO操作時,會為每一個IO設備維護一個Buffer,等待數據輸入到Buffer,從Buffer復制到進程內存空間,都需要時間,根據等待模式可以分為:
1 blocking IO 阻塞式IO (兩段都阻塞)
2 nonblocking IO 非阻塞式IO (第一段不阻塞,第二段阻塞)
3 IO multiplexing IO復用 (兩段都阻塞)
4 signal driven IO 信號驅動IO (第一段不阻塞,第二段阻塞)
5 asynchronus IO 異步IO (兩段都不阻塞)
下面將對以上五種模型做一個詳細的介紹
阻塞式IO
1 用戶線程在讀寫時阻塞,系統調用不返回調用結果並讓當前線程一直阻塞,只有當該系統調用獲得結果或者超時出錯時才返回
如圖:
1 recvfrom 發起系統調用,當內核無數據報準備好時,要等待數據準備 (第一段) 應用進程阻塞
2 當內核數據準備好後,將數據拷貝至用戶空間(第二段)應用進程阻塞 拷貝完成後,返回成功,讓用戶進程去處理數據包,此時阻塞結束,將控制權移交給應用進程
2 缺點
用戶進程在IO過程中被阻塞,不能做任何事情,對CPU的資源利用率不高
非阻塞式IO
1 用戶線程不斷發起IO請求,數據未到達前時系統返回一個狀態值,數據到達後才真正讀取數據(需要用戶線程不斷確定數據報是否已經準備好)
如圖:
1 當用戶進程recvfrom發起一個系統調用,內核無數據包準備好時會返回一個EWOULDBLOCK狀態,當用戶進程不知道內核有沒有準備好數據,需要通過不斷輪詢的方式去確定數據報是否準備好(這個過程用戶進程是非阻塞的)
2 當內核準備好數據後,內核將數據拷貝至進程空間(用戶進程阻塞)
2 缺點
用戶進程每次請求IO都可以立即返回,但是為了拿到數據,需不斷地輪詢,無謂地消耗了大量CPU
IO多路復用(模式介紹不是很詳細,將在後續BIO,NIO中進行詳細介紹)
1 用戶先將需要進行IO操作的socket添加到select中,然後等待阻塞函數select返回,當數據到達後,socket被激活,select返回,用戶線程就能接著發起read請求(註意:阻塞的是select)
這裏涉及到操作系統底層提供的 select,poll,epoll三種機制,這裏舉例為select(將在後續NIO中介紹此種模式的使用)
如圖:
I/O多路復用是通過一種機制,可以監視多個描述符,一旦某個描述符就緒(一般是讀就緒或者寫就緒),能夠通知程序進行相應的讀寫操作
2 優點
可以在單個線程/進程中處理更多的連接
系統開銷小,系統不必創建進程/線程,也不必維護這些進程/線程,從而大大減小了系統的開銷
信號驅動IO
如圖:
1 先開啟套接字的驅動式IO功能,並通過sigachtion系統調用安裝一個信號處理函數,該系統調用立即返回,進程繼續工作,當數據報準備好時,內核為該進程產生一個SIGIO信號 (第一段不阻塞)
2 接收到信號後,再次發起系統調用,由內核將數據包拷貝至用戶空間(第二段阻塞)
異步IO
1 工作機制 告知內核啟動某個操作,並讓內核在整個操作完成後通知我們
如圖:
1 應用進程發起系統調用,內核立即返回一個狀態,此時進程繼續執行
2 當內核準備好數據,並將數據包拷貝至用戶空間後,通知進程處理 (兩段都不阻塞)
總結:
1 阻塞式IO:用戶進程發起系統調用,阻塞用戶進程,內核處理數據報,當兩段全部處理完成後,返回成功指示,再由用戶進程去處理數據報
2 非阻塞式IO:用戶進程發起系統調用,當內核數據報未準備好時,返回一個狀態給用戶進程,用戶進程繼續執行,未阻塞,但需要發起輪詢,不斷地詢問內核數據報是否準備好,當發現數據報已準備好時,阻塞用戶進程,由內核將數據報拷貝至用戶空間,拷貝完成後,返回成功指示,由用戶進程去處理
3 多路復用IO:用戶進程將IO請求註冊到select中,用戶進程繼續執行,select發起系統調用,內核做數據準備,當內核準備好數據時,返回相應用戶進程的可讀指示,用戶進程再發起系統調用,用戶進程阻塞,內核將數據報拷貝至用戶空間,拷貝完成後,返回成功指示,由用戶進程去處理
4 信號驅動IO:用戶進程發起系統調用,當內核數據報未準備好時,返回一個狀態給用戶進程,用戶進程繼續執行,未阻塞,當內核準備好數據時,通過信號通知用戶進程,用戶進程再發起系統調用,用戶進程阻塞,內核將數據報拷貝至用戶空間,拷貝完成後,返回成功指示,由用戶進程去處理
5 異步IO:用戶進程發起系統調用,當內核數據包未準備好是,返回一個狀態給用戶進程,用戶進程繼續執行,未阻塞,當內核準備好數據,並將數據拷貝至用戶空間後,通知用戶進程去直接處理數據報
JAVA - IO模型