兼容性
select() 和 poll() 相對于 信號驅(qū)動和epoll() 在不同os之間的可移植性更高, 但是當fd過多的時候, 效率也遠低于后兩者.
觸發(fā)方式
- poll 和 select 只支持 水平觸發(fā)
- 信號驅(qū)動只支持邊緣觸發(fā)
- epoll支持水平觸發(fā)和邊緣觸發(fā)
select
- select返回的是含有整個句柄的數(shù)組,select 返回后, 程序并不知道是哪些 fd 準備就緒, 而只知道一共有多少個就緒了, 需要進程自己對傳遞過去的集合進行遍歷和判斷
- select的觸發(fā)方式是水平觸發(fā),應用程序如果沒有完成對一個已經(jīng)就緒的文件描述符進行IO操作,那么之后每次select調(diào)用還是會將這些文件描述符通知進程
- 內(nèi)核 / 用戶空間內(nèi)存拷貝問題,select每次都會改變內(nèi)核中的句柄數(shù)據(jù)結構集,因而每次select調(diào)用時都需要從用戶空間向內(nèi)核空間復制所有的句柄數(shù)據(jù)結構,產(chǎn)生巨大的開銷
- 單個進程能夠監(jiān)視的文件描述符的數(shù)量存在最大限制,通常是1024,當然可以更改數(shù)量
poll
- 每個fd都有屬于自身的 pollfd 結構, 它將 感興趣事件和觸發(fā)的事件分成了 events 和 revents. events 的值告訴內(nèi)核我們關心的是描述符的哪些事件 ; 當某個 fd 有事件觸發(fā)了之后, 就由內(nèi)核修改 revents 的數(shù)據(jù), 互不干擾, 所以不必像 select 那樣, 每次調(diào)用都必須重置 fd 集合.
- 數(shù)組大小沒有限制
- 跟 select() 一樣, poll返回后, 程序并不知道是哪些 fd 準備就緒, 而只知道一共有多少個就緒了, 需要進程自己對傳遞過去的集合進行遍歷和判斷
信號驅(qū)動
- 不需要由用戶進程復制fd數(shù)組到內(nèi)核
- 信號處理不好可能會導致進程出問題.
epoll
- epoll 支持水平觸發(fā)和邊緣觸發(fā). epoll 的機制類似于信號驅(qū)動, 都是進程告訴內(nèi)核對哪些 fd 感興趣, 然后對應的fd上有事件的時候, 由內(nèi)核主動通知進程, 進程再進行相應的處理.
- 可以避免復雜的信號處理流程(比如信號隊列溢出時的處理)
- 靈活性高, 可以指定我們希望檢查的事件類型(例如檢查 socket 的讀就緒事件、寫就緒事件、或者兩者都檢查)
總結
select適合少量活躍連接,一般幾千。兼容平臺多。
epoll適合大量不太活躍的連接。