五種I/O模型詳細講解
- 前言
- I/O的本質
- 阻塞IO模型
- 非阻塞IO模型
- 多路復用IO模型
- select
- poll
- epoll
- 信號驅動IO模型
- 異步IO模型
- 總結
前言
I/O的本質
網路IO的本質就是socket流的讀取,通常一次IO讀取會涉及兩個階段與兩個物件,其中兩個物件為:用戶行程(執行緒)Process(Thread)、內核物件(kernel),兩個階段為:等待流資料準備階段、從內核向行程復制資料階段,
對于socket而言,第一步通常等待網路上的資料分組到達,然后被復制到內核的某個緩沖區,第二步資料從內核的緩沖區復制到應用行程的緩沖區,
I/O模型可細分為五種型別:阻塞IO、非阻塞IO、多路復用IO、信號驅動IO、異步IO,
阻塞IO模型
首先,在linux系統中默認所有的IO都是阻塞IO,
阻塞IO的特點是從kernel讀取資料時信號并未立刻回傳,而是等待資料到達完畢或發生錯誤才會回傳結果,這個程序是阻塞的,
術語描述:當用戶行程呼叫recvfrom這個系統呼叫時,kernel就開始等待資料到來,而行程這邊會處于阻塞狀態,當kernel將資料準備好后,就會將資料拷貝到用戶行程的緩沖區,然后kernel回傳結果,用戶行程才會解除block狀態,重新運行起來,

非阻塞IO模型
與阻塞IO不同,當用戶行程發出recvfrom呼叫時,如果kernel中資料還沒有準備好,那么并不會block用戶行程,而是會回傳error錯誤,相對于用戶行程而言,每次發送讀取操作后,并不需要等待,而是會立刻回傳結果,當收到error時,就知道資料未準備完畢,然后繼續發送讀取操作,直到可以直接讀取資料到緩沖區為止,雖然在執行read請求操作時,用戶行程并未阻塞,但是當recvfrom將資料從內核拷貝到行程時,用戶行程處于阻塞狀態,

多路復用IO模型
產生原因: 在具有大量IO請求的場景下,需要應用行程創建多個執行緒去讀取資料,每個執行緒都會呼叫recvfrom去讀取資料,在這種高并發的情況下,可能行程需要創建成千上萬個執行緒,增加服務器負荷,并且造成了嚴重的資源浪費,
因此,有了多路復用IO模型,使用一個執行緒去監聽多個網路請求,即檔案描述符,這樣就實作了使用少量執行緒對大量請求進行監聽,然后再讓對應的執行緒進行資料讀取,那么目前常用select、poll、epoll函式對fd檔案描述符進行監聽,
多路復用IO又稱事件驅動IO,行程使用IO多路復用在兩個階段都是阻塞的狀態,行程使用select函式,其中select函式有一個引數是檔案描述符集合,對這些檔案描述符進行監聽,當檔案描述符就緒時,會回傳readable信號,然后用戶行程呼叫recvfrom進行讀取資料,由于可同時監聽多個IO,效率比阻塞IO高,

select
行程呼叫select后會被阻塞,將需要監聽的檔案描述符放入fd_set,并將fd_set復制到內核空間,內核空間會對fd_set進行輪詢遍歷,若無mark值,則會暫時掛起等待超時時間之后繼續輪詢,直到有資料準備就緒,最后將fd_set復制回用戶行程,進行讀/寫操作,
復雜度O(n)
select的缺點:
1.select監控數量受限
select能監控的fd數量有上限,32位系統一般為1024,64位系統為2048,這個上限可以通過修改引數提高,但是相應的會損失性能,
2.輪詢效率低
對socket進行掃描時是線性掃描,即采用輪詢的方法,效率較低,
3.頻繁拷貝復雜,開銷大
需要維護一個用來存放大量fd的資料結構,用戶空間需要維護一個fd_set,fd_set的每一位都表示一個檔案描述符,開始時會將其發給內核,這會使得用戶空間和內核空間在傳遞該結構時復制開銷大,
4.select是水平觸發
應用程式如果沒有完成對一個已經就緒的檔案描述符進行IO操作,那么之后select呼叫還是會將這些檔案描述符回傳,通知行程,
poll
poll和select基本是一樣的,但是它對fd集合做了優化,使用鏈表存盤,解決了連接數上限的問題,
epoll
epoll的實作與上述兩種方式完全不同,因此不會造成上述的問題,
同select、poll不同,復雜度O(1),通過三個函式實作流程:
1.epoll_create: 創建一個epoll檔案描述符集合,同時底層創建一個紅黑樹和就緒鏈表,紅黑樹存盤所監控的檔案描述符的節點資料,就緒鏈表存盤就緒的檔案描述符的節點資料,
2.epoll_ctl: 用于添加新的描述符,首先判斷紅黑樹中是否存在,如果不存在,插入資料,并告知內核注冊回呼函式(當檔案描述就緒時通過網卡驅動觸發),資料就緒后將事件添加到就緒佇列中,
3.epoll_wait: 檢查鏈表,并將資料拷貝到用戶空間(兩者維護的是片共享記憶體),最后清空鏈表,其中epoll的作業方式分為LT、ET,
注意:epoll是執行緒安全的,但是當一個執行緒呼叫epollwait,而另一個執行緒用epollctl向同一個epoll_fd添加一個監測fd后,epollwait有可能被改fd的讀/寫事件喚醒,

信號驅動IO模型
首先應用行程通過sigaction系統呼叫安裝一個信號處理函式(在內核位置),該系統呼叫立即回傳,行程繼續作業(未被阻塞),當資料準備就緒時,kernel就會為該行程產生一個SIGIO信號,隨后用戶行程就可以使用recvfrom呼叫去讀取資料到記憶體,并回傳成功指示,

異步IO模型
真正意義上的非阻塞IO,當用戶行程發出aio_read操作之后,就立刻可以去做其它的事,另一方面,當kernel的角度,當kernel收到read信號后,會立刻回傳結果,所以不會對用戶行程block,之后,kernel會等待資料準備完畢,然后將資料拷貝到記憶體中,完成之后,kernel會給用戶行程發送signal信號,表示資料已經read操作完畢,整個程序無阻塞狀態的發生,

總結
1.阻塞IO、多路復用IO是兩個階段都處于阻塞狀態,非阻塞IO、信號驅動IO是在第二階段從kernel讀取資料時處于阻塞狀態,異步IO整個程序都未處于阻塞狀態,
2.按照阻塞程度排序:阻塞IO > 非阻塞IO > 多路復用IO > 信號驅動IO > 異步IO ,并且效率由低到高,
3.異步與同步的區別:
在IO模型里面如果請求方從發起請求到資料最后完成的這一段程序中都需要自己參與,那么這種我們稱為同步請求;反之,如果應用發送完指令后就不再參與程序了,只需要等待最終完成結果的通知,那么這就屬于異步,
4.阻塞與非阻塞的區別:
阻塞就是發起讀取資料請求的時,當資料還沒準備就緒的時候,這時請求是即刻回傳,還是在這里等待資料的就緒,如果需要等待的話就是阻塞,反之如果即刻回傳就是非阻塞,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/297539.html
標籤:其他
上一篇:FastDNS中修改IP地址
