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