【NIO系列】——之IO模型

這是【NIO系列】第二篇,歡迎持續關注:java

【NIO系列】——之TCP探祕linux

上一篇咱們講到了關於TCP/IP協議的一些內容,這些是網絡編程的必備知識。在瞭解NIO以前咱們必需要了解一下對應的系統層IO模型,好比java的NIO對應是那種IO模型,阻塞和同步的差別在哪裏,又是否相同。瞭解了這些更方便咱們的後續的NIO探解。編程

1、同步、異步、阻塞、非阻塞

同步、異步,阻塞、非阻塞,這四種狀態常有人分不清,主要是這四種狀態的定義自己也不是很明確,因此各類解答的方式都有。常見的分類有如下:網絡

  1. 同步阻塞IO架構

  2. 同步非阻塞IO異步

  3. 異步非阻塞IOsocket

針對某種IO模型,咱們如何分類,能夠基於POSIX對同步/異步的定義來判別:async

- A synchronous I/O operation causes the requesting process to be blocked until that I/O operation completes;函數

- An asynchronous I/O operation does not cause the requesting process to be blocked;spa

那麼從上咱們能夠看出:

阻塞:是否阻塞主要體如今調用的線程是否能夠幹別的,關注的是程序的等待狀態

同步:是否同步體如今消息通訊機制上 。

也就是說同步和異步說的是消息的通知機制,阻塞非阻塞說的是線程的狀態 。

 

若是說以上的定義依然沒法判別,咱們能夠從輸入操做的兩個階段來看:

通常來講,一個輸入操做一般包括兩個不一樣階段:

(1)等待數據準備好;(2)從內核向進程複製數據。

是否同步的判斷依據是:是否針對的是整個過程,也就是2個階段,是否有阻塞。

是否阻塞的判斷依據是:按程序(線程)等待消息通知時的狀態角度來講的,也就是主要是針對第一階段來講。

 

舉例

咱們舉例來講:

好比說作飯這件事,通常要分爲連個步驟。

一、買菜,準備食材

二、炒菜,作出飯菜

 

方案一:本身動手處理。

一、去超市買菜,準備食材(阻塞,當前時段只能作一件事,且須要持續的等待)

二、回家切菜,炒菜,作出美味飯菜(阻塞,仍是本身來處理)

評價: 方案一同步阻塞。首先階段一是阻塞的,因此認定爲阻塞,兩個階段都是阻塞的,認定爲同步的。

 

方案二:盒馬配送食材,本身作飯

一、網上下單,盒馬配送食材,快遞到了會敲門聯繫你。(非阻塞的,這期間你能夠幹其餘事)

二、拿到菜,切菜、炒菜,作出美味飯菜(阻塞)

評價:方案二爲同步非阻塞。階段一爲非阻塞,認定爲非阻塞。階段二爲阻塞,兩階段中有一個爲阻塞,認定爲同步。

 

方案三:盒馬配送,請阿姨作飯

一、網上下單,盒馬配送食材,快遞到了會敲門聯繫你。(非阻塞的,這期間你能夠幹其餘事)

二、網上請阿姨小時工,幫忙作這一餐,作好通知我。(非阻塞,期間能夠幹其餘事)

評價:方案三爲異步非阻塞。階段一爲非阻塞,認定爲非阻塞。階段二非阻塞,則兩階段中都沒有阻塞,認定爲異步。

那麼是否有異步阻塞IO模型,沒有,要記得異步狀態是包含二個階段的,若是有阻塞的過程,爲什麼還叫異步?

網上有不少介紹有異步阻塞模型的,我目前查到的資料尚未這個證實,如有找到相關論文,還請指教。目前我認爲沒有這個模型的。

 

2、Unix 5種I/O模型

《UNIX網絡編程:卷一》的第六章書中列出了五種IO模型:

  • 阻塞式I/O;

  • 非阻塞式I/O;

  • I/O複用(select,poll,epoll...);

  • 信號驅動式I/O(SIGIO);

  • 異步I/O(POSIX的aio_系列函數);

1.阻塞式I/O

同步阻塞 IO 模型是最經常使用的一個模型,也是最簡單的模型。在linux中,默認狀況下全部的socket都是blocking。它符合人們最多見的思考邏輯。

在這個IO模型中,用戶空間的應用程序執行一個系統調用(recvform),這會致使應用程序阻塞,什麼也不幹,直到數據準備好,等待kernel準備好從網絡上接收到的數據報 + 等待收到的報文被從kernel複製到buf中,recvfrom方法纔會返回,最後進程再處理數據。

這就是阻塞式IO模型

 

2.非阻塞式I/O

非阻塞IO時對一個非阻塞描述符循環調用recvfrom,持續的輪詢(polling),以查看某個操做是否就緒。與阻塞IO不同,"非阻塞將大的整片時間的阻塞分紅N多的小的阻塞, 因此進程不斷地有機會 '被' CPU光顧"。

非阻塞的recvform系統調用調用以後,進程並無被阻塞,內核立刻返回給進程,若是數據還沒準備好,此時會返回一個error。進程在返回以後,能夠乾點別的事情,而後再發起recvform系統調用。如此循環的進行recvform系統調用,檢查內核數據,直到數據準備好,再拷貝數據到進程。拷貝數據整個過程,進程仍然是屬於阻塞的狀態

這就是非阻塞式IO模型

3.I/O複用

IO multiplexing就是咱們說的select,poll,epoll 。爲什麼叫多路複用,是由於它I/O多路複用能夠同時監聽多個fd,如此就減小了爲每一個須要監聽的fd開啓線程的開銷。

select調用是內核級別的,能夠等待多個socket,能實現同時對多個IO端口進行監聽,當其中任何一個socket的數據準好了,就能返回進行可讀而後進程再進行recvform系統調用,將數據由內核拷貝到用戶進程,這個過程是阻塞的。

I/O複用模型會用到select、poll、epoll函數,這幾個函數也會使進程阻塞,可是和阻塞I/O所不一樣的的,這幾個函數能夠同時阻塞多個I/O操做`。並且能夠同時對多個讀操做,多個寫操做的I/O函數進行檢測,直到有數據可讀或可寫時(不是等到socket數據所有到達再處理, 而是有了一部分數據就會調用用戶進程來處理),才真正調用I/O操做函數。

IO複用有人把其成爲同步非阻塞的,也有稱爲同步阻塞。其實這個是否阻塞還須要看第一個階段,第一個階段有的阻塞,有的不阻塞。主要也是阻塞在select階段,屬於用戶主動等待階段,咱們且規範爲阻塞狀態,因此,把IO多路複用歸爲同步阻塞模式

這是IO複用的模型:

 

select、poll、epoll的不一樣

4.信號驅動式I/O

信號驅動式I/O:首先咱們容許Socket進行信號驅動IO,並安裝一個信號處理函數,進程繼續運行並不阻塞。當數據準備好時,進程會收到一個SIGIO信號,能夠在信號處理函數中調用I/O操做函數處理數據。

也就是說第一個階段,徹底是非阻塞的,等數據到達會給一個信號通知,第二個階段recvfrom仍是阻塞過程,和之上無差別。

信號驅動式I/O 過程以下:

5.異步I/O

異步IO不是順序執行,用戶進程進行aio_read系統調用以後,不管內核數據是否準備好,都會直接返回給用戶進程,而後用戶態進程能夠去作別的事情。等到socket數據準備好了,內核直接複製數據給進程,而後從內核向進程發送通知IO兩個階段,進程都是非阻塞的

 

 

總結

針對這5中IO模型,我採用一張圖來總結一下。

 

3、java IO

Unix中的五種I/O模型,除信號驅動I/O外,Java對其它四種I/O模型都有所支持。其中Java最先提供的blocking I/O便是同步阻塞I/O,而NIO便是同步非阻塞I/O,同時經過NIO實現的Reactor模式便是I/O複用模型的實現,經過AIO實現的Proactor模式便是異步I/O模型的實現。

因此說嚴格意義上來講,經過Reactor模式實現的NIO,和unix中的I/O多路複用是相同的概念,但這是一種編程模型,而不是原生支持。這也是咱們下面所要進行的netty講解的主要思想。

 

更多架構知識,歡迎關注個人公衆號,大碼候(cool_wier)

相關文章
相關標籤/搜索