IO多路复用:select、poll、epoll

目录

一、什么是IO多路复用

二、怎么实现IO多路复用

1、select

2、poll

3、epoll

一、什么是IO多路复用

把标准输入、套接字等都看成IO的一路,IO多路复用就是在任何一路I/O有事件发生时,都能通知应用程序去处理响应的事件。

所谓的“事件”包括:
(1)标准输入文件描述符准备好可读;

(2)监听套接字准备好,新连接建立成功;

(3)已连接套接字准备好可写;

(4)发生超时事件,如一个I/O事件等待超过10秒。

二、怎么实现IO多路复用

最简单的实现大概如下:

fd_array = {....}; 

while (true) {

    for (auto i : fd_array) {     // 遍历fd数组

        read/write(fd_array[i], ...);

    }

    sleep(1);

}

使用一个for循环,去不断的遍历fd数组,读写到了就去处理,否则就sleep,不过这里的fd必须设置成非阻塞的,不然会被卡死。

但是这样有很多弊端,比如在sleep的时候可能有事件发生,但如果不sleep,就太耗费CPU了,最好是方法是由内核监听,监听到了事件通知我们,Linux内核提供了三种方式:

1、select

函数原型:

int select(int maxfd, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct timeval *timeout);

返回:若有就绪描述符则为其数目,若超时则为0,若出错则为-1

缺点:所支持的fd个数有限,默认最大值是1024;

2、poll

函数原型:

int poll(struct pollfd *fds, unsigned long nfds, int timeout);

返回值:若有就绪描述符则为其数目,若超时则为0,若出错则为-1

特点:突破了文件描述符最大值的限制,而且每次检测完不会修改原来的传入值,pollfd结构体如下:

struct pollfd {

    int    fd;       /* file descriptor */

    short  events;   /* events to look for */

    short  revents;  /* events returned */

 };

其中events是待检测的事件,检测出来的结果保存到revents里,poll返回的是准备就绪的fd数目,然后还需要遍历revents数组,才能找到对应就绪的fd。

3、epoll

与前两个相比,epoll的性能最好,因为select和poll都需要遍历数组,才能找到就绪的fd,而epoll_wait返回的直接是就绪的fd数组,所以无用功最少,epoll函数主要有三个:

int epoll_create(int size);

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

epoll_create用来创建一个epoll实例,这里的size只要大于0即可,后面可以动态增加或删除,

epoll_ctl返回值: 若成功返回0;若返回-1表示出错

epoll_ctl负责fd的增删改,管理这些fd使用的数据结构是红黑树,所以增加或删除的效率很高;

epoll_wait返回值: 成功返回的是一个大于0的数,表示事件的个数;返回0表示的是超时时间到;若出错返回-1.

如何做到有事件发生立即能感知到呢?是通过设置poll回调。

这里的poll是文件系统针对fd定制的监听事件的机制,通过poll机制可以实现当fd准备就绪后,让底层硬件回调的时候自动把这个fd相关的结构体放到指定队列(就绪列表),并唤醒操作系统,然后只需要遍历就绪列表,就能返回所有已经就绪的fd数组。

所以如果一个”文件“(Linux一切皆文件)所在的文件系统没有实现poll接口,就用不了epoll机制。

目前常见的文件系统,如:ext2、ext4、xfs都没有实现poll接口,除了常见的网络套接字socket外还有几种fd,可以使用epoll机制:

(1)eventfd:用来做事件通知,无法传输数据;

(2)timerfd:定时器事件,到时间点触发可读事件。

除了高效的通知机制外,epoll还有个很好的机制,epoll支持边缘触发(edge-triggered),而poll和select都是条件触发(level-triggered)。

条件触发的意思是只要满足事件的条件,比如有数据需要读,就一直不断地把这个事件传递给用户;而边缘触发的意思是只有第一次满足条件的时候才触发,之后就不会再传递同样的事件了。

参考资料:https://mp.weixin.qq.com/s/0ooBuspqJTR9MSMmqK9_rQ

                  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值