1. 程式人生 > >I/O多路復用之select,poll,epoll簡介

I/O多路復用之select,poll,epoll簡介

重新 才會 增長 文件描述 brush 重新編譯 () 情況 包含

一、select

1.起源

select最早於1983年出現在4.2BSD中(BSD是早期的UNIX版本的分支)。

它通過一個select()系統調用來監視多個文件描述符的數組,當select()返回後,該數組中就緒的文件描述符便會被內核修改標誌位,使得進程可以獲得這些文件描述符從而進行後續的讀寫操作。

2.select的優點

目前幾乎在所有的平臺上支持,具有良好的跨平臺支持。

3.select的缺點

  1. 單個進程能夠監視的文件描述符的數量存在最大限制。默認情況下,在Linux上單個進程能夠打開的最大文件數為1024.(可以通過修改宏定義甚至重新編譯內核的方式提升這一限制)。
  2. select()所維護的存儲大量文件描述符的數據結構,隨著文件描述符數量的增大, 其復制的開銷也線性增長。
  3. 由於網絡相應時間的延遲使得大量的TCP連接處於非活躍狀態,但調用select()會對所有socket進行一次線性掃描,浪費了一定的開銷。
  4. select()所維護的socket連接,kernel中有數據了只會返回稱有數據了,但不會指定socket,還需要對socket進行掃描,找到是哪些socket在kernel中準備了數據,浪費了開銷。

二、poll

1.起源

poll在1986年誕生於System V Release 3,它和select在本質上沒有多大差別,但是poll沒有最大文件描述符數量的限制。

2.poll的優點

沒有最大文件描述符數量的限制。

3.poll的缺點

  1. 包含大量文件描述符的數組被整體復制於用戶態和內核的地址空間之間,而不論這些文件描述符是否就緒,它的開銷隨著文件描述符數量的增加而線性增大。
  2. poll將就緒的文件描述符告訴進程後,如果進程沒有對其進行IO操作,那麽下次調用poll()的時候將再次報告這些文件描述符,所以poll()一般不會丟失就緒的信息,這種方式成為 水平觸發Level Triggered.

4.poll的實際應用

在實際中,poll被認為是select,poll,epoll之間的一個過渡階段,在實際中運用不多。

三、epoll

1.起源

epoll是在Linux2.6中提出的,是之前的select和poll的增強版本。

2.epoll的優點

相對於select和poll來說,epoll更加靈活,沒有描述符限制。

epoll使用一個文件描述符管理多個描述符,將用戶關系的文件描述符的事件存放到內核的一個事件表中,這樣在用戶空間和內核空間的copy只需一次。

epoll是由內核直接支持的實現方法,它幾乎具備了之前所說的一切優點,被公認為Linux2.6下性能最好的多路I/O就緒通知方法。epoll是目前最流行的,目前知名框架Tornado,Nginx,Twisted等都是使用的epoll。

  1. epoll更加靈活,沒有描述符限制。
  2. epoll可以同時支持水平觸發和邊緣觸發(Edge Triggered,只告訴進程哪些文件描述符剛剛變為就緒狀態,它只說一遍,如果我們沒有采取行動,那麽它將不會再次告知,這種方式稱為邊緣觸發),理論上邊緣觸發的性能要更高一些,但是代碼實現相當復雜。
  3. epoll同樣只告知那些就緒的文件描述符,而且當我們調用epoll_wait()獲得就緒文件描述符時,返回的不是實際的描述符,而是一個代表就緒描述符數量的值,你只需要去epoll指定的一個數組中依次取得相應數量的文件描述符即可,這裏也使用了內存映射(mmap)技術,這樣便徹底省掉了這些文件描述符在系統調用時復制的開銷。
  4. 另一個本質的改進在於epoll采用基於事件的就緒通知方式。在select/poll中,進程只有在調用一定的方法後,內核才對所有監視的文件描述符進行掃描,而epoll事先通過epoll_ctl()來註冊一個文件描述符,一旦基於某個文件描述符就緒時,內核會采用類似callback的回調機制,迅速激活這個文件描述符,當進程調用epoll_wait()時便得到通知。
如:epoll監控著100個socket,交給kernel去監測,如果kernel發現只有兩個socket有數據,那麽kernel會告訴用戶具體是哪一個socket有數據,只需要循環去這兩個活躍的socket中收取數據,節省了這部分的開銷。

  註:水平觸發和邊緣觸發(Level Triggered and Edge Triggered)

  水平觸發Level Triggered:在kernel中數據準備好,處於ready的狀態,如果進程沒有對其進行IO操作,數據就還是在kernel中,只有進程再次發送一個recvfrom(system call),觸發後才會將kernel中的就緒的數據拷貝到用戶內存中去。

  邊緣觸發Edge Triggered:和水平觸發相反,數據在kernel中ready後,如果進程沒有對其進行IO操作,那麽就不會再次return readable等信息給進程。數據還是在kernel中,並不會到用戶內存中去。

3.epoll的缺點

僅在支持2.6內核的平臺中支持。

Windows 不支持epoll,支持select。

四、

I/O多路復用之select,poll,epoll簡介