IO復(fù)用模型

一、多進(jìn)程和多線(xiàn)程的本質(zhì)

  • 多個(gè)執(zhí)行單位競(jìng)爭(zhēng)CPU時(shí)間片

執(zhí)行單位大部分時(shí)間都在阻塞等待客戶(hù)端的數(shù)據(jù)到來(lái)(阻塞在read()或者accept())
活躍的就那么幾個(gè)
就緒態(tài),調(diào)度,分配時(shí)間片,運(yùn)行態(tài),恢復(fù)CPU現(xiàn)場(chǎng)
PCB保存了寄存器等信息
執(zhí)行單位之間的切換太多,消耗了大量的時(shí)間

  • 每個(gè)執(zhí)行單位中都有一個(gè)socket
    上面的這個(gè)呢,被我們稱(chēng)為阻塞的模型——

缺點(diǎn)是CPU切換太頻繁

二、非阻塞輪詢(xún)模型

  • 只啟動(dòng)一個(gè)進(jìn)程,然后這個(gè)進(jìn)程中來(lái)輪詢(xún)每個(gè)套接字,把每個(gè)套接字都設(shè)置成非阻塞的,每個(gè)套接字都read()一遍,不斷地輪詢(xún)遍歷

缺點(diǎn)是CPU可能會(huì)不斷空轉(zhuǎn),即使沒(méi)有數(shù)據(jù)CPU的使用率也會(huì)很高,即使加入一個(gè)sleep(),但是會(huì)導(dǎo)致實(shí)時(shí)性變差
優(yōu)點(diǎn)是沒(méi)有了阻塞模型中執(zhí)行單位之間的切換

三、IO復(fù)用 模型

  • IO復(fù)用 = 反應(yīng)堆
  • 套接字就是IO

四、select

  • 只能支持1024個(gè)文件描述符(1024位對(duì)應(yīng)的是128個(gè)字節(jié))
  • 反應(yīng)堆fd_set

每一個(gè)文件描述符是否在這個(gè)fd_set集合中,在的話(huà)就置1

  • select()函數(shù)是用來(lái)監(jiān)聽(tīng)文件描述符集合fd_set
  • select也是阻塞的,除非有一個(gè)文件描述符被觸發(fā)了

select有3個(gè)反應(yīng)堆

  • 處理返回的fd_sets就叫解復(fù)用

select是輪詢(xún)的方式來(lái)監(jiān)聽(tīng)反應(yīng)堆的,我們可以看第一個(gè)參數(shù)是maxfds + 1來(lái)得知其本質(zhì)

  • 最后一個(gè)參數(shù)timeout是一個(gè)結(jié)構(gòu)體
  • NULL:一直阻塞,直到監(jiān)聽(tīng)的反應(yīng)堆里面有數(shù)據(jù)
  • timeout = 10:到了超時(shí)時(shí)間,就會(huì)返回,返回值可能為0也可能比0大
  • timeout = 0:直接返回,不會(huì)阻塞等待,相當(dāng)于非阻塞
  • listenfd監(jiān)聽(tīng)的數(shù)據(jù)是TCP層的數(shù)據(jù)(比如SYN報(bào)文,FIN報(bào)文),不是應(yīng)用層的數(shù)據(jù)
  • 反應(yīng)堆fd_sets在select()中是一個(gè)傳入傳出參數(shù),傳入是告知監(jiān)聽(tīng)哪些文件描述符,傳出是告知有多少個(gè)文件描述符可讀
  • 時(shí)間復(fù)雜度是O(n)

五、poll

  • poll——舉手
  • poll反應(yīng)堆(傳入和傳出區(qū)分開(kāi)了)——結(jié)構(gòu)體數(shù)組

所以poll是不需要重新初始化反應(yīng)堆的,但是select需要
ulimit -a
/etc/limit.conf文件修改打開(kāi)文件的數(shù)量

  • 時(shí)間復(fù)雜度是O(n)(處理n個(gè)連接)

  • poll的timeout——一個(gè)整型數(shù)

-1表示阻塞,0表示立即返回非阻塞,>0表示定時(shí)

  • select反應(yīng)堆(傳入傳出參數(shù)整合在了一起)——文件描述符集合

需要重新初始化反應(yīng)堆

  • select的timeout——結(jié)構(gòu)體

六、epoll

  • 維護(hù)一棵樹(shù)(內(nèi)核空間中)
  • LT

隔一段時(shí)間就會(huì)檢查是否從0變?yōu)榱?,不能夠及時(shí)地反饋

  • ET

可以捕捉的到0變?yōu)?的時(shí)刻,所以(錯(cuò)過(guò)了這個(gè)邊緣,就永遠(yuǎn)都檢測(cè)不出來(lái)事件觸發(fā)了,但是LT則是后面只要是1,就會(huì)檢測(cè)出來(lái))

  • EPOLLONESHOT

用完一次后(只監(jiān)聽(tīng)一次),監(jiān)聽(tīng)完后會(huì)從樹(shù)上摘下來(lái)

  • epollfd是一棵樹(shù)的文件描述符

  • epoll_event是一個(gè)隊(duì)列(用戶(hù)空間),當(dāng)有事件觸發(fā)的時(shí)候,內(nèi)核epoll_wait()會(huì)自動(dòng)把對(duì)應(yīng)節(jié)點(diǎn)的內(nèi)容填充到就緒隊(duì)列

  • timeout跟poll中是一樣的

  • 返回值:有多少個(gè)fd被觸發(fā) 了

就緒隊(duì)列是以一個(gè)數(shù)組來(lái)實(shí)現(xiàn)的


  • 節(jié)點(diǎn)的具體內(nèi)容(val)是epoll_event

  • close套接字文件描述符的時(shí)候,還要記著從反應(yīng)堆中去除

  • O(log2N)是想象在整個(gè)樹(shù)上只有一個(gè)節(jié)點(diǎn)被觸發(fā),找到這個(gè)節(jié)點(diǎn)的最大復(fù)雜度是O(log2N)

  • 高效的情景:1000個(gè)連接10個(gè)活躍

1000個(gè)連接1000個(gè)活躍的話(huà),epoll還不如poll,因?yàn)閑poll比poll多維護(hù)一棵樹(shù)

epoll還不如poll,因?yàn)閑poll比poll多維護(hù)一棵樹(shù)

  • key-value, key是fd,value是epoll_event
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容