IO复用函数统共有三个,select,poll,epoll,但是在大并发条件下,我们一般都会使用epoll,select和poll有下边两个缺点。
- 每次在调用之前都要把所有需要监控的socket都传给内核
- 无论是在内核还是在用户空间select和poll都是采用轮询的方式检查所有socket
而epoll正是在这两点上做出了改进,得到了比select和poll更高的效率。
epoll的原理
linux的epoll模块在操作系统启动的时候创建了一个自己的文件系统和两个内核cache,这便是epoll给自己搭建的舞台。每次我们执行epoll_create的时候返回的文件描述符就是在这个文件系统中创建的一个新文件。
除了在epoll文件系统里创建一个新的文件节点,并且返回给用户以外,epoll_create还在内核cache里初始化了一棵红黑树,用来存放用户向epollfd注册的socket事件。
除了红黑树,另一个关键的数据结构是就绪链表。这个链表用来存放就绪事件的fd,当用户调用epoll_wait时,会检测这个链表是否为空,如果不为空就把链表中的数据copy到用户传来的event数组中,然后返回,为空就开始sleep,到了timeout就算链表为空也直接返回。
当用户执行epoll_ctl向epollfd添加socket的时候,除了把socket放到红黑树中,还会给内核中断处理程序注册一个回调函数,告诉内核如果这个socket上有数据要处理就把它放到就绪链表里。
epoll的优点
1.可以打开大量的文件描述符。这一点select可以通过修改宏,并且重新编译内核来实现,但是epoll本身就具备打开大量描述符的能力。支持的FD上限只和内存有关系,在