epoll为何比select和poll快----select poll epoll之间的对比

select:

       int select(int nfds, fd_set *readfds, fd_set *writefds,
                  fd_set *exceptfds, struct timeval *timeout);

通过位图的数据结构来设置监听的文件描述符,对应位为1表示该文件描述符需要监听。受fd_set的限制最多只能监听1024个文件描述符,其函数第二,三,四个参数都是文件描述符集,每次调用select都需要将文件描述符集拷贝到内核中,内核通过遍历nfds次(因为内核不知道你到底将那个位 置为1了,需要遍历到你设置的最大文件描述符上,这也就是为什么nfds要传监听的最大文件描述符+1)fd_set来判断是否有事件发生,若有事件发生则将事件对应的文件描述符集相应位 置为1并返回到用户空间。


poll:

与select不同的是poll使用的是struct pollfd结构体数组,所以它可以突破1024上限。

           struct pollfd {
               int   fd;         /* file descriptor */
               short events;     /* requested events */
               short revents;    /* returned events */
           };

并且其通过events和revents将监听的事件类型与发生的事件类型分离了,简化了代码,调用poll后,将struct pollfd数组从用户空间拷贝到内核,内核遍历数组,若有事件发生则设置revents返回到用户空间。


epoll与select和poll不同的是:

1.epoll不用在每次调用的时候都要将数据结构拷贝到内核,其通过epoll_create在内核建立一颗红黑树和就绪链表,通过epoll_ctl可以将关心的文件描述符和其关心的事件状态挂到红黑树上,避免每次调用都要拷贝数据结构。

2.不需要遍历关心的文件描述符,其向红黑树加入一个fd的同时注册了一个回调函数,当fd有事件发生时,内核调用回调函数把fd加入到就绪链表中。所以epoll_wait函数只会去看就绪链表是否有数据,有数据时,则将数据拷贝到events数组,并清空链表(若fd没有设置ET模式且缓冲区内有数据则将fd重新加入到就绪链表中),然后返回。无数据时,若函数设置为阻塞模式则阻塞等待。若设置非阻塞模式则直接返回。若设置超时时间则该时间内有数据拷贝返回,超出该时间则直接返回。**

3.epoll_wait返回后不像select和poll不告诉你那些文件描述符发生了事件,需要循环去判断epoll_wait返回的events数组里面全是发生的事件,且其返回值为发生的事件的个数,我们只需一个一个去处理就好了。


总结:

1.epoll减少了文件描述符从用户态到内核态的拷贝

2.减少了对监听文件描述符的遍历

3.返回的都是发生事件的fd,不需要额外的循环做判断。

发布了31 篇原创文章 · 获赞 4 · 访问量 941

猜你喜欢

转载自blog.csdn.net/qq_39781096/article/details/104782953