以前打算總結一下Java的BIO(IO),AIO,NIO,最後一步步深刻,發現Unix(Linux)的IO模型須要提早掌握,因此先總結一下Unix的IO模型。linux
Unix網絡編程中介紹了五種IO模型,分別是:阻塞IO、非阻塞IO、IO多路複用、信號驅動IO、異步IO。
Java的IO模型與Unix的IO模型的對應關係以下所示(這個對應關係並不嚴格):編程
Java-IO模型 | Unix-IO模型 |
---|---|
BIO | 阻塞式IO |
NIO | IO多路複用 |
AIO | 異步IO |
在進行IO模型講解以前,先講講數據的兩個狀態:內核態和用戶態。
咱們將文件從磁盤加載到內存中。操做系統是怎麼作的?
第一步:由於咱們的全部程序,都是和操做系統的內核進行交互,因此文件首先是從磁盤加載到內核,這時候文件是處於內核態。
第二步:文件從內核再加載到內存中,應用程序此時才能夠在內存中進行讀寫操做。這個時候的文件就是內核態。
因此Unix的五種IO模型的不一樣指出,就是這兩個步驟的處理流程不一樣。網絡
這種模式很簡單,系統給調用recvfrom函數以後,線程一直處於等待狀態,一直等到:
第一步文件加載到內核態完成,第二步文件加載到用戶態完成。異步
系統不停的經過recvfrom進行輪詢,一直到第一步完成,而後在第二步阻塞式的將數據從內核態加載到用戶態。
這裏的非阻塞IO模式,主要是指第一步,加載數據到內核態,這個過程是非阻塞的,經過輪詢來判斷數據是否在內核準備好。socket
系統首先經過select,阻塞式的查看內核數據是否準備完畢。
當內核數據加載完成以後,系統會調用recvfrom,將內核態的數據加載到用戶態。
這裏看起來第一步和第二步都是阻塞式操做,可是,select能夠在極小代價的狀況下,同時處理多個文件句柄(包括socket)。函數
第一步,至關於系統註冊一個回調函數,當內核數據準備好了以後通知我。
此時系統能夠作其餘的事情,並不須要阻塞式的等待內核數據。
第二步,阻塞式調用recvfrom,將內核的數據加載到用戶態。spa
這個模型在理論上來講,是真正的異步模型,由於在以上四種模型中,在第二步:數據從內核態加載到用戶態,都是同步操做。
而在該模型中,系統在加載文件的時候,只須要經過aio_read註冊一個回調,當文件完成了內核態,用戶態的加載以後,通知當前系統。
在這個過程當中,系統不用等待,能夠執行其餘的運算任務。操作系統
這張圖是對以上五種IO模型的彙總比較,總的來講,越靠後的模型在理論上來講就越高效。
前面的四種IO模型【阻塞IO、非阻塞IO、IO多路複用、信號驅動IO】,都屬於同步IO,只有最後一種模型是真正的異步【異步IO】.net
由於select是輪詢的模式,不停的檢查文件句柄的狀態。
epoll是callback的模式,當文件句柄準備好了以後,直接進行回調,更高效。線程
在Windows系統下,經過IOCP實現。
在Linux系統下,沒有,由於Linux系統下的AIO底層還是epoll。
(我的猜想,這也是爲何Netty使用了NIO,而沒有使用AIO)
以對話的形式講述,比較易於理解
漫話:如何給女友解釋什麼是Linux的五種IO模型?
數據的內核態,用戶態,這篇文章也有講到,同時介紹了高效的數據傳輸方式:
zero-copy