多路复用IO模型中的select和epoll
Posted HelloWorld搬运工
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多路复用IO模型中的select和epoll相关的知识,希望对你有一定的参考价值。
一,前提知识——文件描述符fd
1、文件描述符简介
首先从文件描述符开始讲起。因为,对于内核而言,所有打开的文件都是通过文件描述符引用的。那么文件描述符到底是什么?
文件描述符(file descriptor)通常是一个小的非负整数,内核用以标识一个特定进程正在访问的文件。当打开一个现有文件或创建一个新文件时,内核向进程返回一个文件描述符。当读、写一个文件时,使用 open 或 create 返回的文件描述符标识该文件,将其作为参数传送给 read 或 write。
我的理解,文件描述符就是内核用来标识某进程正在访问文件的一个标志。
二,概念介绍
select,poll,epoll都是IO多路复用的机制。I/O多路复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。但select,poll,epoll本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的,而异步I/O则无需自己负责进行读写,异步I/O的实现会负责把数据从内核拷贝到用户空间。
三,select流程
1, 拿到所有需要轮询的文件描述符fd,从用户空间拷贝到内核空间。
2, 注册回调函数。
3, 遍历所有的fd。
4, 调用poll,返回是否读写就绪的mask掩码。
5,遍历结束,进入睡眠(超时重新唤起遍历或者回调epoll唤起)。
6,继续遍历,从3开始。
7,结束,将所有fd重新拷贝回用户空间。
select的几大缺点:
(1)每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大
(2)同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大
(3)select支持的文件描述符数量太小了,默认是1024
四,epoll的改进
首先在select里需要在每次调用select都会拷贝fd。epoll只拷贝一次。
原因是:
select和poll都只提供了一个函数——select或者poll函数。而epoll提供了三个函数,epoll_create, epoll_ctl 和epoll_wait,epoll_create是创建一个epoll句柄;epoll_ctl是注册要监听的事件类型;epoll_wait则是等待事件的产生,epoll的解决方案在epoll_ctl函数中。每次注册新的事件到epoll句柄中时(在epoll_ctl中指定EPOLL_CTL_ADD),会把所有的fd拷贝进内核,而不是在epoll_wait的时候重复拷贝。epoll保证了每个fd在整个过程中只会拷贝一次
而且epoll的回调函数不是返回是否读写就绪,而是直接将就绪的fd拷贝加入一个就绪链表。所以epoll的遍历唤醒时不用像select一样再遍历一遍fd集合,而只需要看一下就绪链表是否为空,如果不为空进行读写即可。
还有select有fd的支持数量只有1024,而epoll无限制,只被系统内存限制,测试中1G内存可以支持10W左右。cat /proc/sys/fs/file-max可以查看。
以上是关于多路复用IO模型中的select和epoll的主要内容,如果未能解决你的问题,请参考以下文章
[Linux网络编程]多路IO复用Epoll Select问题补充