select
通过数组实现的运行队列,当绑定的任务数据没有到达进程时会让出CPU。
当网卡接收到数据,然后网卡通过中断信号通知 CPU 有数据到达,执行中断程序,中断程序主要做了两件事:
1)将网络数据写入到对应 socket 的数据接收队列里面;
2)唤醒队列中的等待进程 A,重新将进程 A 放入 CPU 的运行队列中;

1.性能开销大
1)调用 select 时会陷入内核,这时需要将参数中的 fd_set 从用户空间拷贝到内核空间,select 执行完后,还需要将 fd_set 从内核空间拷贝回用户空间,高并发场景下这样的拷贝会消耗极大资源;(epoll 优化为不拷贝)
2)进程被唤醒后,不知道哪些连接已就绪即收到了数据,需要遍历传递进来的所有 fd_set 的每一位,不管它们是否就绪;(epoll 优化为异步事件通知)
3)select 只返回就绪文件的个数,具体哪个文件可读还需要遍历;(epoll 优化为只返回就绪的文件描述符,无需做无效的遍历)
2.同时能够监听的文件描述符数量太少。受限于 sizeof(fd_set) 的大小,在编译内核时就确定了且无法更改。一般是 32 位操作系统是 1024,64 位是 2048。(poll、epoll 优化为适应链表方式)
第 2 个缺点被 poll 解决,第 1 个性能差的缺点被 epoll 解决。
poll
管理多个描述符也是进行轮询,根据描述符的状态进行处理,但 poll 无最大文件描述符数量的限制,因其基于链表存储。
select 和 poll 在内部机制方面并没有太大的差异。相比于 select 机制,poll 只是取消了最大监控文件描述符数限制,并没有从根本上解决 select 存在的问题。
epoll
基于红黑树的数据结构优化了poll的检索效率问题,同时通过就绪队列维护就绪事件,无需做无效的遍历


Comments NOTHING