Linux高並發機制——epoll模型


epoll是一個特別重要的概念,常常用於處理服務端的並發問題。當服務端的在線人數越來越多,會導致系統資源吃緊,I/O效率越來越慢,這時候就應該考慮epoll了。epoll是Linux內核為處理大批句柄而作改進的poll,是Linux特有的I/O函數。其特點如下:

    1.epoll是Linux下多路復用IO接口select/poll的增強版本。其實現和使用方式與select/poll有很多不同,epoll通過一組函數來完成有關任務,而不是一個函數。

    2.epoll之所以高效,是因為epoll將用戶關心的文件描述符放到內核里的一個事件表中,而不是像select/poll每次調用都需要重復傳入文件描述符集或事件集。比如當一個事件發生(比如說讀事件),epoll無須遍歷整個被偵聽的描述符集,只要遍歷那些被內核IO事件異步喚醒而加入就緒隊列的描述符集合就行了。

    3.epoll有兩種工作方式,LT(level triggered):水平觸發和ET(edge-triggered):邊沿觸發。LT是select/poll使用的觸發方式,比較低效;而ET是epoll的高速工作方式。

    通俗理解就是,比如說有一堆女孩,有的很漂亮,有的很鳳姐。現在你想找漂亮的女孩聊天,LT就是你需要把這一堆女孩全都看一遍,才可以找到其中的漂亮的(就緒事件);而ET是你的小弟(內核)將N個漂亮的女孩編號告訴你,你直接去看就好,所以epoll很高效。另外,還記得我的上一篇文章中小明找女神聊天的例子嗎?采用非阻塞方式,小明還需要每隔十分鍾回來看一下(select);如果小明有小弟(內核)幫他守在大門口,女神回來了,小弟會主動打電話,告訴小明女神回來了,快來處理吧!這就是epoll。

    epoll共有三個函數,如下:

   

  1. 1、int epoll_create(int size)  
  2.   // 創建一個epoll句柄,參數size用來告訴內核監聽的數目,size為epoll所支持的最大句柄數  


  1. 2、int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)  
  2.    /*函數功能: epoll事件注冊函數 
  3.   參數epfd為epoll的句柄,即epoll_create返回值 
  4.   參數op表示動作,用3個宏來表示:   
  5.     EPOLL_CTL_ADD(注冊新的fd到epfd),  
  6.      EPOLL_CTL_MOD(修改已經注冊的fd的監聽事件), 
  7.     EPOLL_CTL_DEL(從epfd刪除一個fd); 
  8.     其中參數fd為需要監聽的標示符; 
  9.   參數event告訴內核需要監聽的事件,event的結構如下:*/  
  10.     struct epoll_event {  
  11.       __uint32_t events; //Epoll events  
  12.       epoll_data_t data; //User data variable  
  13.     };  
  1. 3、 int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout)  
  2. //等待事件的產生,函數返回需要處理的事件數目(該數目是就緒事件的數目,就是前面所說漂亮女孩的個數N)  


因此,服務端epoll的時候,步驟如下:

    1.調用epoll_create函數在Linux內核中創建一個事件表;

    2.然后將文件描述符(監聽套接字)添加到所創建的事件表中;

    3.在主循環中,調用epoll_wait等待返回就緒的文件描述符集合;

    4.分別處理就緒的事件集合

下面介紹下如何將一個socket添加到內核事件表中,如下:

   

    1. //將文件描述符fd添加到epollfd標示的內核事件表中, 並注冊EPOLLIN和EPOOLET事件,EPOLLIN是數據可讀事件;EPOOLET表明是ET工作方式。最后將文件描述符設置非阻塞方式  
    2. /** 
    3.   * @param epollfd: epoll句柄 
    4.   * @param fd: 文件描述符 
    5.   * @param enable_et : enable_et = true,  
    6.      采用epoll的ET工作方式;否則采用LT工作方式 
    7. **/  
    8. void addfd( int epollfd, int fd, bool enable_et )  
    9. {  
    10.     struct epoll_event ev;  
    11.     ev.data.fd = fd;  
    12.     ev.events = EPOLLIN;  
    13.     if( enable_et )  
    14.         ev.events = EPOLLIN | EPOLLET;  
    15.     epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev);  
    16.     setnonblocking(fd);  
    17.     printf("fd added to epoll!\n\n");  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM