BIO 和 NIO 的區別和原理
BIO
BIO(Blocking IO) 又稱同步阻塞 IO,一個客戶端由一個線程來進行處理
當客戶端建立連接後,服務端會開闢線程用來與客戶端進行連接。以下兩種情況會造成 IO 阻塞:
-
服務端會一直阻塞,直到和客戶端進行連接
-
客戶端也會一直阻塞,直到和服務端進行連接
基於 BIO,當連接時,每有一個客戶端,服務就開啓線程處理,這樣對資源的佔用是非常大的;如果使用線城市來做優化,當大量連接時,服務端也會面臨無空閒線程處理的問題。那麼怎麼設計才能讓單個線程能夠處理更多請求,而不是一個。所以 NIO 就被提出。
NIO
NIO(Non Blocking IO)又稱同步非阻塞 IO。服務器實現模式爲把多個連接 (請求) 放入集合中,只用一個線程可以處理多個請求(連接),也就是多路複用。
NIO 有 3 大核心組件:
-
Buffer:緩衝區,buffer 底層就是數組
-
Channel:通道,channel 類似於流,每個 channel 對應一個 buffer 緩衝區
-
Selector:多路複用器,channel 會註冊到 selector 上,由 selector 根據 channel 讀寫事件的發生將其交由某個空閒的線程處理
這樣就大大提升了連接的數量,用於接收請求。
NIO 目前有三個函數(模型)
-
select
-
poll
-
epoll
Select 函數
Select 是 Linux 提供的一個函數,可以將一批fd一次性傳遞給內核,然後由內核去遍歷,來確定哪個fd符合,並提供給用戶空間
Select 函數處理過程
-
將用戶空間的
fd數組拷貝到內核空間 -
內核空間會遍歷
fd數組,查看是否有數據到達 -
遍歷所有
fd,將當前進程掛到每個fd的等待隊列中 -
當設備收到一條消息(網絡設備)或填寫完文件數據(磁盤設備)後,會喚醒設備等待隊列上睡眠的進程,隨後
當前進程就會被喚醒 -
遍歷完成後,如果有數據到達,返回有數據到達的
fd的數量,並對用戶空間的fd做標記 -
如果無數據到達,則
當前進程進入睡眠,當有某個fd有I/O事件或當前進程睡眠超時後,當前進程重新喚醒再次遍歷所有fd文件 -
用戶空間在此循環遍歷,沒有標記的
fd不處理,只有標記的fd纔會去處理
Select 存在的問題
-
fd數量有限制:單個進程所打開的fd是有限制的,通過FD_SETSIZE設置,默認 1024 -
fd拷貝耗時:每次調用select,需要將fd數組從用戶空間拷貝到內核空間 -
內核空間遍歷耗時:內核空間通過遍歷的方式,查看
fd是否有數據到達,這是一個同步的過程 -
找到
fd後,返回的是數量,而不是fd本身:select返回的是fd的數量,具體是哪個還需要用戶自己遍歷
Poll 函數
Poll 也是 Linux 提供的內核函數,poll 和 select基本是一致,唯一的區別在於它們支持的fd的數量不一致
-
select : 只能監聽 1024 個
fd -
poll :無限制,操作系統支持多少,poll 就可以支持多少
Epoll 函數
poll解決了select函數的fd數量問題,而epoll解決了select、poll函數其餘問題:
-
fd數量有限制:poll已經解決此問題 -
fd拷貝耗時:內核空間中保存一份fd數組,無需用戶每次都重新傳入,只需要告訴內核修改的部分即可 -
內核空間遍歷耗時:內核空間不再通過遍歷的方式找
fd,而是通過異步 IO 事件喚醒 -
找到
fd後,返回的是數量,而不是fd本身:內核空間會通過異步 IO 事件,將fd返回給用戶,用戶無需在遍歷整個fd數組
因此,epoll 提供 3 個函數,來處理上述改進的方案:
-
epoll_create:創建 epoll 句柄 -
epoll_ctl:向內核空間添加,修改,刪除需要監控的fd -
epoll_wait、epoll_pwait:類似select函數
sourc:www.cnblogs.com/reim/p/16968278.html
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/apSNn8Up-B0ENZ8rzEiNTQ