一、多進(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_eventclose套接字文件描述符的時(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







