多路复用IO模型中的select和epoll

版权声明:如需转载,请附上原文链接即可 https://blog.csdn.net/doujinlong1/article/details/84072555

多路复用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流程

imagef74c416b09205492.png

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可以查看。

猜你喜欢

转载自blog.csdn.net/doujinlong1/article/details/84072555