select poll 与epoll模型的总结
select()和poll() IO多路復用模型
select優(yōu)點:
1.一次可以等待多個文件描述符,減少了平均等待時間
2.客戶越來越多時,減輕了進程調度的壓力(相較于多進程多線程服務器)
select缺點:
1.能監(jiān)聽的文件描述符有上限,這個上限是由fd_set決定的。
2.它返回的只是就緒事件的個數(shù),要判斷是那個事件滿足,需要遍歷文件描述符。
3.select監(jiān)聽的集合是輸入輸出參數(shù),每次監(jiān)聽都需要重新初始化。
4.每次調用select,都需要把fd集合從用戶態(tài)拷貝到內核態(tài),這個開銷在fd很多時會很大
5.內核采用輪詢(遍歷fd集合)的方式來檢測就緒事件,這個開銷在fd很多時也很大
6.select和poll都只能工作在低效的LT(水平觸發(fā))模式
poll優(yōu)點:
1.poll監(jiān)聽的文件描述符沒有最大數(shù)量的限制
2.poll對于select來說包含了一個pollfd結構,pollfd結構包含了要監(jiān)視的event和發(fā)生的revent,而不像select那樣使用輸入輸出的傳遞方式。所以不需要每次監(jiān)聽都初始化
poll缺點:
1.數(shù)量過大以后其效率也會線性下降。
2.poll和select一樣也是返回就緒事件的個數(shù),需要遍歷文件描述符來判斷是那個事件已經就緒,當數(shù)量很大時,開銷也就很大。
3.select和poll都只能工作在低效的LT(水平觸發(fā))模式
4.每次調用poll,都需要把pollfd數(shù)組從用戶態(tài)拷貝到內核態(tài),這個開銷在fd很多時會很大
5.內核采用輪詢(遍歷pollfd數(shù)組)的方式來檢測就緒事件,這個開銷在fd很多時也很大
拿select模型為例,假設我們的服務器需要支持100萬的并發(fā)連接,則在__FD_SETSIZE 為1024的情況下,則我們至少需要開辟1k個進程才能實現(xiàn)100萬的并發(fā)連接。除了進程間上下文切換的時間消耗外,從內核/用戶空間大量的無腦內存拷貝、數(shù)組輪詢等,是系統(tǒng)難以承受的。因此,基于select模型的服務器程序,要達到10萬級別的并發(fā)訪問,是一個很難完成的任務。
因此,該epoll上場了。
epoll IO多路復用模型實現(xiàn)機制
由于epoll的實現(xiàn)機制與select/poll機制完全不同,上面所說的?select的缺點在epoll上不復存在。
設想一下如下場景:有100萬個客戶端同時與一個服務器進程保持著TCP連接。而每一時刻,通常只有幾百上千個TCP連接是活躍的(事實上大部分場景都是這種情況)。如何實現(xiàn)這樣的高并發(fā)?
在select/poll時代,服務器進程每次都把這100萬個連接告訴操作系統(tǒng)(從用戶態(tài)復制句柄數(shù)據(jù)結構到內核態(tài)),讓操作系統(tǒng)內核去查詢這些套接字上是否有事件發(fā)生,輪詢完后,再將句柄數(shù)據(jù)復制到用戶態(tài),讓服務器應用程序輪詢處理已發(fā)生的網絡事件,這一過程資源消耗較大,因此,select/poll一般只能處理幾千的并發(fā)連接。
epoll的設計和實現(xiàn)與select完全不同。epoll通過在Linux內核中申請一個簡易的文件系統(tǒng)(文件系統(tǒng)一般用什么數(shù)據(jù)結構實現(xiàn)?紅黑樹)。把原先的select/poll調用分成了3個部分:
1)調用epoll_create()建立一個epoll對象(在epoll文件系統(tǒng)中為這個句柄對象分配資源)
2)調用epoll_ctl向epoll對象中添加這100萬個連接的套接字
3)調用epoll_wait收集發(fā)生的事件的連接
如此一來,要實現(xiàn)上面說是的場景,只需要在進程啟動時建立一個epoll對象,然后在需要的時候向這個epoll對象中添加或者刪除連接。同時,epoll_wait的效率也非常高,因為調用epoll_wait時,并沒有一股腦的向操作系統(tǒng)復制這100萬個連接的句柄數(shù)據(jù),內核也不需要去遍歷全部的連接。
下面來看看linux內核具體的epoll機制實現(xiàn)思路。
當某一進程調用epoll_create方法時,Linux內核會創(chuàng)建一個eventpoll結構體,這個結構體中有兩個成員與epoll的使用方式密切相關。eventpoll結構體如下所示:
[cpp]?view plaincopy每一個epoll對象都有一個獨立的eventpoll結構體,用于存放通過epoll_ctl方法向epoll對象中添加進來的事件。這些事件都會掛載在紅黑樹中,如此,重復添加的事件就可以通過紅黑樹而高效的識別出來(紅黑樹的插入時間效率是lgn,其中n為樹的高度)。
而所有添加到epoll中的事件都會與設備(網卡)驅動程序建立回調關系,也就是說,當相應的事件發(fā)生時會調用這個回調方法。這個回調方法在內核中叫ep_poll_callback,它會將發(fā)生的事件添加到rdlist雙鏈表中。
在epoll中,對于每一個事件,都會建立一個epitem結構體,如下所示:
[cpp]?view plaincopy當調用epoll_wait檢查是否有事件發(fā)生時,只需要檢查eventpoll對象中的rdlist雙鏈表中是否有epitem元素即可。如果rdlist不為空,則把發(fā)生的事件復制到用戶態(tài),同時將事件數(shù)量返回給用戶。
epoll數(shù)據(jù)結構示意圖
從上面的講解可知:通過紅黑樹和雙鏈表數(shù)據(jù)結構,并結合回調機制,造就了epoll的高效。
OK,講解完了Epoll的機理,我們便能很容易掌握epoll的用法了。一句話描述就是:三步曲。
第一步:epoll_create()系統(tǒng)調用。此調用返回一個句柄,之后所有的使用都依靠這個句柄來標識。
第二步:epoll_ctl()系統(tǒng)調用。通過此調用向epoll對象中添加、刪除、修改感興趣的事件,返回0標識成功,返回-1表示失敗。
第三部:epoll_wait()系統(tǒng)調用。通過此調用收集收集在epoll監(jiān)控中已經發(fā)生的事件。
epoll優(yōu)點:
1.epoll維護的描述符數(shù)目不受到限制,而且性能不會隨著描述符數(shù)目的增加而下降。(不需要遍歷整個文件描述符)
2.epoll先通過epoll_ctl注冊一個描述符到內核中,并一直維護著而不像poll每次操作都將所有要監(jiān)控的描述符傳遞給內核
3.在描述符讀寫就緒時,通過回掉函數(shù)將自己加入就緒隊列中,之后epoll_wait返回該就緒隊列,所以用戶不需要遍歷整個文件描述符判斷哪些事件就緒。性能提升。
4.支持ET高效模式。
poll和select適用于關心描述符個數(shù)多的應用程序。其中epoll對于每次只有很少描述符就緒很有優(yōu)勢(采用回調機制監(jiān)測描述符就緒)。
總結
以上是生活随笔為你收集整理的select poll 与epoll模型的总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c++实现单例类(懒汉与饿汉)
- 下一篇: 经典的大数据例题