close
文章出處

上一篇文章中,談了一些網絡編程的基本概念。在現實使用中,用的最多的就是I/O復用了,無非就是select,poll,epoll

很多人提到網絡就說epoll,認為epoll效率是最高的。單純的這么認為,其實有失偏頗。epoll固然高效,可是它是怎么做到高效的,它到底比select或poll優異在哪兒?

我們通過調用流程來簡單分析下。

首先以select為例(poll類似),看下其調用過程

1.選擇想要處理的套接字,通過接口FD_SET(fd, &set)加入到set中;

2.調用select(max+1, &set,,..)

3.對set中所有套接字調用FD_ISSET(fd,&set),查看fd上是否有事件發生

select存在的問題

  1. 單個進程能夠監視的文件描述符的數量存在最大限制,通常是1024,當然可以更改數量,但由于select采用輪詢的方式掃描文件描述符,文件描述符數量越多,性能越差;(在linux內核頭文件中,有這樣的定義:#define __FD_SETSIZE    1024)
  2. 內核 / 用戶空間內存拷貝問題,select需要復制大量的句柄數據結構,產生巨大的開銷;
  3. select返回的是含有整個句柄的數組,應用程序需要遍歷整個數組才能發現哪些句柄發生了事件;
  4. select的觸發方式是水平觸發,應用程序如果沒有完成對一個已經就緒的文件描述符進行IO操作,那么之后每次select調用還是會將這些文件描述符通知進程。

epoll調用過程

1 .epoll_create 創建一個epoll對象,一般epollfd = epoll_create()

2 .epoll_ctl (epoll_add/epoll_del的合體),往epoll對象中增加/刪除某一個流的某一個事件

比如epoll_ctl(epollfd, EPOLL_CTL_ADD, socket, EPOLLIN);//注冊緩沖區非空事件,即有數據流入     

      epoll_ctl(epollfd, EPOLL_CTL_DEL, socket, EPOLLOUT);//注冊緩沖區非滿事件,即流可以被寫入

添加事件的時候,其實是向內核注冊了一個回調函數。回調函數作用是,在相應的套接字上發生事件時,將其加入到epoll對象的時間就緒鏈表中,而這是在內核完成的。

3 epoll_wait(epollfd,...),獲取就緒事件。即從就緒事件鏈表中取出所有的事件。

可以看到epoll比select高效的地方在于,其返回的就是所有已經發生事件的套接字,而不需要像select那樣需要在用戶態去判斷每個套接字上是否有事件發生。

另外,在調用select時,內核需要去一一檢測傳入的套接字集合是否有事件,而調用epoll_wait時,只是將內核中的就緒數據取出而已

如果有n個連接,并且這n個連接都有事件發生,那么使用select與epoll其實并沒有多少區別。對于select來說,用戶態對每一個套接字的事件監測都是有效的。

但是select有一個問題是,每次去調用select之前,都要重置套接字set。如果連接數很大,每次FD_SET(fd, &set)調用接口,也會對性能造成不小的影響。而epoll中,只需調用一次epoll_ctl即可。

所以,在連接數很大,且活躍連接不多的情況下,使用epoll有明顯的優勢;而如果連接數較少,且連接基本都是活躍的,其實select的效果反而會更好。


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 AutoPoster 的頭像
    AutoPoster

    互聯網 - 大數據

    AutoPoster 發表在 痞客邦 留言(0) 人氣()