BIO 和 NIO 的區別和原理

BIO

BIO(Blocking IO) 又稱同步阻塞 IO,一個客戶端由一個線程來進行處理

當客戶端建立連接後,服務端會開闢線程用來與客戶端進行連接。以下兩種情況會造成 IO 阻塞:

  1. 服務端會一直阻塞,直到和客戶端進行連接

  2. 客戶端也會一直阻塞,直到和服務端進行連接

基於 BIO,當連接時,每有一個客戶端,服務就開啓線程處理,這樣對資源的佔用是非常大的;如果使用線城市來做優化,當大量連接時,服務端也會面臨無空閒線程處理的問題。那麼怎麼設計才能讓單個線程能夠處理更多請求,而不是一個。所以 NIO 就被提出。

NIO

NIO(Non Blocking IO)又稱同步非阻塞 IO。服務器實現模式爲把多個連接 (請求) 放入集合中,只用一個線程可以處理多個請求(連接),也就是多路複用。

NIO 有 3 大核心組件:

  1. Buffer:緩衝區,buffer 底層就是數組

  2. Channel:通道,channel 類似於流,每個 channel 對應一個 buffer 緩衝區

  3. Selector:多路複用器,channel 會註冊到 selector 上,由 selector 根據 channel 讀寫事件的發生將其交由某個空閒的線程處理

這樣就大大提升了連接的數量,用於接收請求。

NIO 目前有三個函數(模型)

Select 函數

Select 是 Linux 提供的一個函數,可以將一批fd一次性傳遞給內核,然後由內核去遍歷,來確定哪個fd符合,並提供給用戶空間

Select 函數處理過程

  1. 將用戶空間的fd數組拷貝到內核空間

  2. 內核空間會遍歷fd數組,查看是否有數據到達

  3. 遍歷所有fd,將當前進程掛到每個fd的等待隊列中

  4. 當設備收到一條消息(網絡設備)或填寫完文件數據(磁盤設備)後,會喚醒設備等待隊列上睡眠的進程,隨後當前進程就會被喚醒

  5. 遍歷完成後,如果有數據到達,返回有數據到達的fd的數量,並對用戶空間的fd標記

  6. 如果無數據到達,則當前進程進入睡眠,當有某個fdI/O事件或當前進程睡眠超時後,當前進程重新喚醒再次遍歷所有fd文件

  7. 用戶空間在此循環遍歷,沒有標記的 fd不處理,只有標記fd纔會去處理

Select 存在的問題

  1. fd數量有限制:單個進程所打開的fd是有限制的,通過 FD_SETSIZE 設置,默認 1024

  2. fd拷貝耗時:每次調用 select,需要將fd數組從用戶空間拷貝到內核空間

  3. 內核空間遍歷耗時:內核空間通過遍歷的方式,查看fd是否有數據到達,這是一個同步的過程

  4. 找到fd後,返回的是數量,而不是fd本身select返回的是fd的數量,具體是哪個還需要用戶自己遍歷

Poll 函數

Poll 也是 Linux 提供的內核函數,poll 和 select基本是一致,唯一的區別在於它們支持的fd的數量不一致

Epoll 函數

poll解決了select函數的fd數量問題,而epoll解決了selectpoll函數其餘問題:

  1. fd數量有限制poll已經解決此問題

  2. fd拷貝耗時:內核空間中保存一份fd數組,無需用戶每次都重新傳入,只需要告訴內核修改的部分即可

  3. 內核空間遍歷耗時:內核空間不再通過遍歷的方式找fd,而是通過異步 IO 事件喚醒

  4. 找到fd後,返回的是數量,而不是fd本身:內核空間會通過異步 IO 事件,將fd返回給用戶,用戶無需在遍歷整個fd數組

因此,epoll 提供 3 個函數,來處理上述改進的方案:

  1. epoll_create:創建 epoll 句柄

  2. epoll_ctl:向內核空間添加,修改,刪除需要監控的fd

  3. epoll_waitepoll_pwait:類似 select函數

sourc:www.cnblogs.com/reim/p/16968278.html
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/apSNn8Up-B0ENZ8rzEiNTQ