1. 什么是IO?
在計算機中無時無刻不存在着對數據的訪問和讀取(數據都存儲在物理的媒介上,例如寄存器,高速緩存,內存,磁盤,網卡等等),這些操作被稱為IO。
2. 阻塞IO
(1)當用戶線程發起IO請求后,會進行系統調用(system call)來讓內核(Kernel)進行IO操作
(2)此時用戶線程阻塞,等待內核將數據准備好
(3)內核將數據准備好后會將數據從內核空間拷貝到用戶空間,並返回給用戶線程結束阻塞。
3. 非阻塞IO
(1) 由用戶線程發起IO請求, 進行系統調用來讓內核進行IO操作
(2) 此時如果內核沒有准備好數據則會直接返回error,並不會阻塞用戶線程,用戶線程可以重復的發起IO請求
(3)當用戶線程發起請求並且內核已經將數據准備好后,會將數據從內核空間拷貝到用戶空間(這個過程是需要阻塞用戶線程的),返回給用戶
4. 多路復用IO
(1)用戶線程調用select后進行系統調用(內核會監視所有select負責的socket),此時用戶線程被阻塞
(2)當內核將數據准備好后就會返回,並通知用戶線程進行讀取操作,此時內核將數據拷貝到用戶空間並返回
5. 異步IO
(1)用戶線程進行aio_read,進行系統調用切換到內核
(2)內核立即返回,並不會阻塞用戶線程
(3)內核准備好數據后會將數據從內核空間拷貝到用戶空間並通知用戶線程操作已完成
6. 阻塞IO與非阻塞IO?
阻塞IO:用戶線程發起IO操作,緊接着由內核線程來執行IO操作,在阻塞IO中內核線程並不會立即返回而是等待數據拷貝到內存空間時才返回,在此期間用戶線程處於阻塞狀態。
非阻塞IO: 與阻塞IO不同,內核線程在執行IO操作后會立即返回,若結果為error則用戶線程可以重新發起請求而不會被阻塞,一旦內核將數據准備好了且用戶線程發起了IO請求那么將數據拷貝到用戶空間。
我們看上面的圖可以知道IO操作大致分為兩個部分:
(1)用戶線程發起IO請求時,內核未准備好數據
(2)用戶線程發起IO請求時,內核以准備好數據
通過對比兩個圖中流程我們可以發現,(2)這個流程在阻塞IO與非阻塞IO流程是相同的區別在於(1)這個步驟。因此阻塞IO與非阻塞IO的區別在於內核線程在執行IO操作時是否立即返回結果,若立即返
回則為非阻塞IO,反之則為阻塞IO。
7. 同步與異步IO?
異步IO: 用戶線程發起IO操作后,可以立即去做其他事情,另一方面,對於內核線程當它收到異步讀取之后會立即返回,不會對用戶線程造成阻塞。當內核將數據准備好之后會將數據從內核空間拷貝到用戶空間,內核會發送 給用戶一個信號通知用戶IO操作已完成。
同步IO: 同步IO的關鍵在於在真正讀取數據(也就是上面提到的(2)這個步驟)的時候用戶線程是否被阻塞。非阻塞IO雖然在用戶發起請求時會立即返回,但是當內核准備好數據之后,任然需要用戶線程發起請求才會將數據 從內核空間拷貝到用戶空間,因此非阻塞IO屬於同步IO。
8. 異步IO與非阻塞IO的區別?
異步IO與非阻塞IO的區別在於,當用戶線程發起一次IO操作不需要再次去確認內核是否准備好數據。異步IO中內核准備好數據后會將數據從內核空間自動拷貝到用戶空間。
9. 總結
最后統一的總結一下:
用戶進程發起請求從內核中獲取數據那么這時候有兩種情況:
(1)操作系統還沒有准備后數據,那么這時候怎么辦,有兩種方法:
a. 讓用於進程等着(這種情況就是阻塞)
b. 如果沒有數據就返回一個ERROR,不需要用戶進程干等(這種情況就是非阻塞)
(2)過了一會兒操作系統准備好數據了,這時候又有兩種方法:
a. 啥也不管,等着用戶進程再次來請求才把數據給它(這種情況就是同步)
b. 負責到底,數據准備好,直接給到用戶進程,並且還發出一個信號,告訴用戶進程數據已經准備好(這種情況就是異步)
因此,我們可以發現:不管是阻塞IO,還是非阻塞IO都是同步IO。