從操作系統內核看 Java 非阻塞 IO 事件檢測

Ver68X 7年前發布 | 14K 次閱讀 Socket IO Java Java開發

非阻塞服務器模型最重要的一個特點是,在調用讀取或寫入接口后立即返回,而不會進入阻塞狀態。在探討單線程非阻塞IO模型前必須要先了解非阻塞情況下Socket事件的檢測機制,因為對于非阻塞模式最重要的事情是檢測哪些連接有感興趣的事件發生,一般會有如下三種檢測方式。

應用程序遍歷socket檢測

如圖所示,當多個客戶端向服務器請求時,服務器端會保存一個socket連接列表,應用層線程對socket列表進行輪詢嘗試讀取或寫入。對于讀取操作,如果成功讀取到若干數據則對讀取到的數據進行處理,讀取失敗則下個循環再繼續嘗試;對于寫入操作,先嘗試將數據寫入指定的某個socket,寫入失敗則下個循環再繼續嘗試。

這樣看來,不管多少個socket連接都可以被一條線程管理起來,一條線程負責遍歷這些socket列表,不斷地嘗試讀取或寫入數據,很好地利用了阻塞的時間,處理能力得到提升。但這種模型需要在應用程序中遍歷所有的socket列表,同時需要處理數據的拼接,連接空閑時可能也會占用較多CPU資源,不適合實際使用。對此改進是使用事件驅動的非阻塞方式。

內核遍歷socket的事件檢測

這種方式將socket的遍歷工作交給了操作系統內核,對socket遍歷的結果組織成一系列的事件列表并返回應用層處理。對于應用層,他們需要處理的對象就是這些事件,這就是其中一種事件驅動的非阻塞方式的實現。

如圖所示,服務器端有多個客戶端連接,應用層向內核請求讀寫事件列表。內核遍歷所有socket并生成對應的可讀列表readList和可寫列表writeList,readList標明了每個socket是否可讀,例如socket1的值為1,表示可讀,socket2的值為0,表示不可讀。writeList則標明了每個socket是否可寫。應用層遍歷讀寫事件列表readList和writeList,做相應的讀寫操作。

內核遍歷socket的方式已經不用在應用層對所有socket進行遍歷,將遍歷工作下移到內核層,這種方式有助于提高檢測效率。但是它需要將所有連接的可讀事件列表和可寫事件列表傳到應用層,假如socket連接數量大起來的話,列表從內核復制到應用層也是不小的開銷。另外,當活躍連接較少時,內核與應用層之間存在很多無效的數據拷貝,因為它是將活躍和不活躍的連接狀態都拷貝到應用層了。

內核基于回調的事件檢測

通過遍歷的方式檢測socket是否可讀可寫是一種效率比較低的方式,不管是在應用層遍歷還是在內核遍歷。所以需要另外一種機制來優化遍歷的方式,那就是回調函數。內核中socket都對應一個回調函數,當客戶端往socket發送數據時,內核從網卡接收數據后就會調回調函數將此socket作為可讀事件加入到事件列表中。應用層獲取此事件列表即可得到所有感興趣的事件。

如圖所示,服務器端有多個客戶端socket連接,首先應用層告訴內核每個socket感興趣的事件;接著當客戶端發送數據過來時,對應會有一個回調函數,內核從網卡復制數據成功后即調回調函數將socket1作為可讀事件event1加入到事件列表,同樣地,內核發現網卡可寫時就將socket2作為可寫事件event2添加到事件列表中;最后,應用層向內核請求讀寫事件列表,內核將包含了event1和event2的事件列表返回應用層,應用層通過遍歷事件列表得知socket1有數據待讀取,于是進行讀操作,而socket2則可以寫入數據。

這種方式由操作系統內核維護客戶端的所有連接并通過回調函數不斷更新可讀可寫事件列表,而應用層線程只要遍歷這些事件列表即可知道可讀取或可寫入的連接,進而對這些連接進行讀寫操作。極大提高了檢測效率,自然處理能力也更強。

上面介紹了三種非阻塞的事件檢測機制,對于Java來說,非阻塞IO的實現完全是基于操作系統內核的非阻塞IO,它將操作系統的非阻塞IO的差異屏蔽了并提供統一的API,讓我們不必關心操作系統。JDK會幫我們選擇非阻塞IO的實現方式,例如對于Linux系統,在支持epoll的情況下JDK會優先選擇用epoll實現Java的非阻塞IO。這種非阻塞方式的事件檢測機制就是效率最高的“內核基于回調的事件檢測”。

 

 

來自:https://mp.weixin.qq.com/s?__biz=MjM5MzA1Mzc3Nw==&mid=2247483667&idx=1&sn=316f9b08e43bb11c1b8c2cb2f1eec548&chksm=a69dac2d91ea253b4c1e62ab13b385bd4987f2bdabb1db2cad6c3f40d0b456b4f1951f637a5d#rd

 

 本文由用戶 Ver68X 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!