1.啥是IO?
2.講明白同步和阻塞倆概念
3.啥是IO多路複用,作業系統層的演進
4.對比BIO,NIO,AIO
四步玩轉IO模型
1.啥是IO
計算機核心三大功能: Input 計算 OutPut
IO重要吧 沒有IO計算機變成玩具,
那IO又可分為幾種 常用的,磁盤IO 網絡IO
閉眼睛想 如果IO不給力,計算機運算能力再牛逼 會不會影響整體效率的,非常影響
從底層磁盤看IO: 啥是磁盤IO
2. 同步與阻塞
同步與異步,指的是API,接口,服務調用等層面的概念。
同步指的是一步一步來,上一步執行完 傳回結果 才能執行下一步, 異步指的是 不需要等上一步執行完傳回結果,就能執行下一步。
舉個簡單的例子就是 java線程池, 把具體的任務丢到線程池裡就不管了,主線程可以繼續幹别的事了,不需要阻塞在那等任務執行完,線程池主要的目的也是為了完成異步。
通常異步的執行可以通過回調接口來擷取執行結果,如FutureTask,可以擷取到異步執行的情況
阻塞與非阻塞,指的是底層作業系統IO層面的概念。
阻塞指的是 程序調用作業系統執行IO,IO執行完成之前,程序會一直阻塞在那等待,直到IO完成擷取到傳回結果
非阻塞指的是 程序調用作業系統執行IO,IO沒有完成會直接傳回失敗結果,程序循環去調用直到IO完成,或者IO完成後作業系統回調接口來通知程序拿資料。總而言之 程序不需要在那一動不動的阻塞住等IO 這就是非阻塞。
現在差別開同步和阻塞,一個是應用接口調用層面,一個是底層作業系統IO層面,兩者的思想很相近
模拟一個場景:
我們這台機器作為服務端,另一台機器作為用戶端
用戶端請求建立一次網絡連接配接,随後通過網絡傳輸資料
此時在我們機器讀取資料過程

我們建立一個線程,用來監聽新建立的Socket,讀取發來的資料
阻塞式IO:
線程調用read函數,如果沒有資料發來 就一直阻塞,
資料從網卡傳到核心态,核心緩沖區複制到使用者緩沖區,傳輸過程中線程保持阻塞狀态, 直到拿到資料傳回結果
非阻塞IO:
不用等資料傳輸完,即可傳回給線程一個結果(-1 或失敗), 這樣可以放開線程去幹别的事,
需要使用者線程循環調用 read,直到傳回值不為 -1,再開始處理業務。
但是這樣有個明顯的缺點 線程想拿到資料 就得不斷一遍一遍調用,一遍一遍詢問資料傳好了沒有, 也會有不小的開銷,
多線程并發執行的情況下 每一個Socke監聽都會耗着一個線程,消耗線程資源
IO多路複用 select:
不再為每一次Socket監聽建立一個線程了,而是一個線程同時服務多個Socket套接字
在使用者态,每建立一個套接字 添加一個檔案描述符fd 到數組裡
使用者态将fd數組拷貝到核心态,執行select函數
select函數 讓核心去周遊數組中的每個元素,執行非阻塞的判斷,判斷是否Socket準備好資料了
最後select傳回準備好的fd個數,通知使用者态
使用者态執行read函數去讀資料
優點:
由核心态做周遊,有效的減少了每次周遊判斷要經過使用者态 核心态之間切換 !!
問題:
1.select傳回結果隻是fd個數,具體哪個fd準備好了還要使用者态自己周遊 !!
2.select需要拷貝fd數組到核心态,高并發場景下消耗較大
3.select在周遊的過程中也是阻塞的,使用者态需要阻塞的等待核心态傳回結果
IO多路複用 poll:
poll隻是在select基礎上增強,它和 select 的主要差別就是,去掉了 select 隻能監聽 1024 個檔案描述符的限制。
IO多路複用 epoll:
1. 核心中儲存一份檔案描述符集合,無需使用者每次都重新傳入,隻需告訴核心修改的部分即可。
2. 核心不再通過輪詢的方式找到就緒的檔案描述符,而是通過異步 IO 事件喚醒。
3. 核心僅會将有 IO 事件的檔案描述符傳回給使用者,使用者也無需周遊整個檔案描述符集合。
總結一下 整個過程,
IO多路複用解決的問題是,我的服務端同時和十個用戶端建立連接配接 等着用戶端發資料,那我怎麼随時随地直到哪個用戶端發資料了 我好讀資料呢?
原始辦法就是每一個連接配接 建立一個線程阻塞的等待用戶端消息,這顯然不夠友好
IO多路複用就通過一個線程同時監聽十個用戶端,輪訓着用戶端套接字 哪個好了通知我讀哪個不就好了。
如果輪訓周遊是在使用者态完成的,每一次判斷資料準備好都要使用者态切核心态,核心态切使用者态 這樣是不是效率很低?
索性把是個用戶端代表的檔案描述符傳到核心态,讓核心态去周遊,周遊出結果再告訴使用者态就完了呗。
最後的read讀資料 還是要使用者态去讀。隻不過是有确定的去讀
4.對比BIO,NIO與AIO
BIO: 也稱同步阻塞IO,顧名思義 應用調用層是同步的,作業系統層是阻塞的。 可以參考java InputStream流,當read磁盤資料時,read()方法會阻塞在那,而底層也會阻塞在那等待IO完成
NIO: 也稱同步非阻塞IO,應用調用層是同步的,作業系統層是非阻塞的。 如果基于NIO進行網絡通信,采取的就是多路複用的IO模型,這個多路複用IO模型針對的是網絡通信中的IO場景來說的。
AIO: 也成異步非阻塞IO,也叫做NIO2.0 異步IO模型,應用調用層是異步的,作業系統層是非阻塞的。應用層調用不管IO是否成功都會直接傳回,不會阻塞住線程。你需要提供一個回調函數給AIO接口,一旦底層系統核心完成了具體的IO請求,比如網絡讀寫之類的,就會回調你提供的回調函數。