通常來講,一個輸入操做一般包括兩個階段:
是否同步的判斷依據是: 是否 針對的 整個過程,即2個階段,是否有阻塞
是否阻塞的判斷依據是: 按 程序等待消息通知時的狀態角度來講的,,即針對第一階段來講
例子很形象:
Linux 認爲
一、用系統調用 read 從 socket 裏讀取 一段數據
二、用系統調用read 從 一個磁盤文件讀取一段數據到 內核
分 網路IO 和 磁盤文件 IO。 網絡IO 才作 BLOCK。
一個解釋是,所謂「Block」是指操做系統能夠預見這個Block會發生纔會主動Block。
例如當讀取TCP鏈接的數據時,若是發現Socket buffer裏沒有數據就能夠肯定定對方尚未發過來,因而Block;
而對於普通磁盤文件的讀寫,也許磁盤運做期間會抖動,會短暫暫停,可是操做系統沒法預見這種狀況,只能視做不會Block,照樣執行。
一、Unix 5中 IO模型
- 阻塞式I/O;
- 非阻塞式I/O;
- I/O複用(select,poll,epoll...);
- 信號驅動式I/O(SIGIO);
- 異步I/O(POSIX的aio_系列函數);
一、阻塞式I/O;
同步阻塞IO模型是最經常使用的一個模型。 linux中 默認狀況下全部的socket都是 blocing,
在這個模型中,用戶空間的應用程序執行一個系統調用 recvform, 這會致使應用程序阻塞,睡沒也不幹,直到數據準備好,等待 kenel準備好 從 網絡上姐都到的 數據包 + 等待收到的報文 被 從 kernel 賦值到bug中,recvform 方法纔會返回,最後 進程在處理數據。
2 非阻塞式I/O
非阻塞IO, 對一個非阻塞描述符 循環調用 recvfrom,持續的輪詢(polling),以查看某個操做是否就緒。與阻塞IO不同,非阻塞將大的 整片時間的阻塞 分紅 N多的小的阻塞, 全部 進程 不斷的有機會 被 CPU 光顧。
非阻塞的 recvfrom 系統調用後,進程並無被阻塞,內核立刻返回給進程,若是數據沒有準備好,會返回 error。 進程在返回以後,能夠幹其餘事情,而後在發起recvfrom 系統調用。如此循環的僅從 recvfrom 系統調用,檢查內核數據,直到數據準備好,在拷貝數據到進程。拷貝數據整個過程,進程仍然是屬於 阻塞的狀態。
3.I/O複用
IO multiplexing 就是咱們說的 select,poll,epoll。(多路複用,由於它 能夠同時監聽多個 fd, 減小了爲每一個須要監聽的fd 開啓線程的開銷)
select 調用是內核級別的,能夠等待多個socket,能實現同時多多個 IO端口進行監聽, 當其中任何一個socket 的數據準備好了,就能返回進行 可讀(寫),而後進程在進行 recvform 系統調用,將數據由 內核 拷貝到用戶進程,這個過程是阻塞的。
IO複用模型會用到 select,poll,epoll函數,這幾個函數也會使進程阻塞,可是和阻塞IO所不一樣的, 這幾個函數能夠同時阻塞多個 IO操做,多個寫操做的 IP函數 進行檢測,直到有數據 可讀或可寫 時(不是等到socket數據所有到達再處理, 而是有了一部分數據就會調用用戶進程來處理),才進行真正地調用 IO操做函數。
IO複用有人把其成爲同步非阻塞的,也有稱爲同步阻塞。其實這個是否阻塞還須要看第一個階段,第一個階段有的阻塞,有的不阻塞。主要也是阻塞在select階段,屬於用戶主動等待階段,咱們且規範爲阻塞狀態,因此,把IO多路複用歸爲同步阻塞模式。
4.信號驅動式I/O
信號驅動式I/O:首先咱們容許Socket進行信號驅動IO,並安裝一個信號處理函數,進程繼續運行並不阻塞。當數據準備好時,進程會收到一個SIGIO信號,能夠在信號處理函數中調用I/O操做函數處理數據。
也就是說第一個階段,徹底是非阻塞的,等數據到達會給一個信號通知,第二個階段recvfrom仍是阻塞過程,和之上無差別。
5.異步I/O
異步IO不是順序執行,用戶進程進行aio_read系統調用以後,不管內核數據是否準備好,都會直接返回給用戶進程,而後用戶態進程能夠去作別的事情。等到socket數據準備好了,內核直接複製數據給進程,而後從內核向進程發送通知。IO兩個階段,進程都是非阻塞的。
總結
二、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模型的實現。