select和epoll的区别

select原理概述:
1、将用户空间的fd_set拷贝到内核空间;
2、注册回调函数__pollwait;
3、遍历所有的fd,对于每个文件描述符都去调用f_op->poll函数;
4、当设备就绪时,就会唤醒设备上的等待队列的所有节点,于是当前进程就获得了一个完成的信号。poll操作完成时,返回的是一组掩码mask,通过遍历这个掩码上的位是否为1或者0,重新设置用户传进来的fd_set,其中各个位是当前描述符上的不同的就绪事件;
5、只要有事件发生,系统调用返回,就将当前内核的fd_set拷贝到用户空间,在用户空间对于相对fd进行读写或者异常处理;

epoll原理概述:
1、epoll_create的作用:
创建一个文件系统eventpoll,并将sockfd所对应的inode,file结构关联起来;
2、epoll_ctl的作用:
将用户关心的每一个描述符以epitem节点的形式都添加到红黑树中,或者从红黑树中将描述符对应的epitem节点删除,或者改变红黑树的节点epitem节点所关心的事件;
3、epoll_wait的作用:
等待文件操作完成时,设备驱动会去调用每一个描述符所注册的回调函数,并将每一个就绪的描述符的节点添加到eventpoll文件系统中的就绪列表rdlist,然后又通过与用户mmap的一块共享空间,返回给用户就绪事件;

两种模式的区别:
LT模式下,只要一个描述符fd上的数据没有一次性处理完,会在以后调用epoll_wait时,将此描述符重新返回;ET模式下,只会通知一次;

两种模式的实现:
监听的描述符上有事件就绪时,内核会把该句柄,插入到就绪链表rdlist中,这时调用epoll_wait时,内核会把rdlist上有就绪事件发生的描述符拷贝给用户空间,然后清空rdlist,最后epoll_wait会检查这些socket,如果是LT模式,sockfd上有数据没有处理完,那么现在内核会把它重新挂载到就绪链表rdlist上,等到调用epoll_wait时,返回给用户空间;如果是ET模式,那么就算sockfd上还有事件发生,是不会重新返回给用户的;所以,LT模式,知道sockfd有事件没有处理完,就会重新将描述符返回给用户;

select缺点:
1、select处理的描述符的数量是有限的,最多只能使用1024个,虽然我们可以改变这个内核所限制的最大处理数,但是通过以往的大佬们的经验,如果将此值改变,对于select的性能会产生影响的;
2、效率低,每次都需要线性扫描fd_set集合,集合越大,速度越慢;
3、用户内核空间的数据拷贝;

epoll的优点:
1、对于并发处理的文件描述符没有限制,仅受系统中进程打开最大文件描述符个数的限制,Linux-2.6.11.12可以打开的最大文件描述符的个数为65535;
2、效率高,每次只要有就绪事件发生,就会调用描述符所对应的回调函数,将此描述符插入到就绪链表rdlist中,将就绪队列中的描述符返回给用户;
3、epoll拷贝数据的时候,是通过内核用户空间共同mmap一块内存,进行数据的交互的;

那么小伙伴们有没有一个疑问:select一定没有epoll高效么???回答当然不是呀,那么接下来我们就说一说原因!!!

select适用于连接少,活动连接多的情况;而epoll适用于连接多,活动链接少的情况;

解释上面的原因:
1、当连接少的时候,select,只是需要建立几个链表的节点,并将就绪事件相对应的位置为1,返回给用户空间;而epoll无论连接多少,都需要将建立一个文件系统,相对于select,系统空间的资源没能充分使用;所以这种情况下适合用select;
2、当连接多的时候,select用户内核拷贝数据,每次都需要线性扫描fd_set集合,集合越大,速度越慢,而epoll刚开始的时候,建立的疑问文件系统去管理用户关心的描述符,为每一个描述符都注册了一个回调函数,当有就绪事件发生时,直接将就绪描述符插入到就绪链表rdlist中,直接将这个链表返回给用户态,拷贝数据的时候,又是通过mmap一个的共享内存,所以从遍历速率和拷贝数据的效率上来说,epoll是更占优势的;
3、当活动连接多的时候;比如现在用户注册的事件总数为500个,刚好这500个连接同时都有事件就绪了,无论有几个连接有就绪事件,select都需要从头遍历到尾,并将就绪事件相对应的位置为1,执行的是位操作;而epoll,同时有500个活动连接,那么会同时触发CPU去执行自己的回调函数,这样的情况下,就会发生”惊群现象”,每个CPU只能在一个时刻执行一个回调函数,但是设备驱动会不停试图想去获取CPU,这样系统会做一些无效的调度,或者上下文切换,导致效率降低;所以,这种情况下,select比epoll高效;

你可能感兴趣的:(linux)