5种IO模型(select,poll,epoll)

IO模型有5种,包括阻塞IO,非阻塞IO,信号驱动IO,异步IO,以及多路转接IO。最后一部分单独描述。
首先

  1. 阻塞IO
    概念:在内核准备好数据之前,系统调用会一直等待数据,将数据从内核态拷贝到用户态后,返回系统调用。
    特点:流程简单,顺序化处理,但对资源的利用率不高。

  2. 非阻塞IO
    概念:如果内核还没有将数据准备好,系统调用会直接返回,返回错误码。通过循环的方式反复尝试读写文件描述符,指到内核准备好数据,返回系统调用。
    特点:流程较为复杂,也是顺序化处理,不够实时。

  3. 信号驱动IO
    概念:通过定义SIGIO信号处理(就绪信号),系统调用向内核发送信号,内核进行处理,等内核将数据准备好的时候,向系统调用发送SIGIO信号,通知可以进行IO操作,开始拷贝数据。
    特点:较非阻塞IO来说,具有较好的实时性,效率也有所提高,但流程更加复杂。

  4. 异步IO
    概念:通过定义IO完成信号处理,发起异步调用,由内核完成IO操作(数据拷贝完成后),通知系统调用。
    特点:无时序(采用非阻塞方式)内核独立完成具体IO操作,完成后通过信号通知系统。

同步通信和异步通信:

强调流程流程是否顺序化完成
1)同步:发起一个调用时,如果没有及时得到结果,调用将一直等待,直到返回结果。
调用者会主动等待调用的结束。
异步:调用者发起一个调用,调用发出后就立刻返回,没有收到结果。被调用者完成后在通知调用者。
强调功能的完成方式—任务是否是自己完成
2)同步:要完成一个功能,要是条件不具备会一直等待,知道满足条件后自己完成。
异步:完成一个功能,但并不会自己完成,由系统完成任务。

优缺点:同步处理流程简单,同一时间占用资源少,异步调用效率高,占用资源多。

阻塞与非阻塞:
阻塞:调用结果返回之前,进程将一直等待,进程将被挂起,等满足条件后在返回。
非阻塞:即使不能立即得到结果,但也不会将进程挂起。

异步阻塞:调用者发起异步调用,调用并不会立即返回,而是等待系统完成。
异步非阻塞:调用者发起异步调用,立即返回,不等待系统完成。

select多路转接

需求提出:避免对没有就绪的操作符进行操作,而导致阻塞,效率降低。对大量的IO就绪事件进行监控,让我们的进程只针对就绪的IO进行操作。就绪事件包括可读事件,可写事件,异常事件。
select多路转接过程:
1.定义指定事件集合,初始化集合,将所需要监控的事件描述符添加入集合中。
2.发起调用,将集合中的数据拷贝至内核中,发起轮询遍历进行监控。
3.调用返回后,集合中存在的事件都是就绪事件的描述符,没有就绪的事件将被移除

相关函数:

#include<sys/select.h>
int select(int nfds,fd_set* readfds,fd_set* writefds,fd_set* exceptfds,struct timeval *timeout )
nfds—就绪事件总和+1;
readfds—检测的可读事件描述符;
writefds—检测的可写事件描述符;
exceptdfs—检测的异常事件描述符;
timeout—等待时间;(null 一直等待,select将被阻塞;0 仅检查事件集合状态,立刻返回;具体timeval结构数字 监控的时间)

函数返回值:
执行成功返回就绪事件的个数
0–表示没有事件完成,timeout返回
-1–表示存在错误

select一次能够监控的事件个数是1024;
fd_set是一个结构体,里面只有一个整数数组,相当于位图,操作位图的接口:

void FD_ZERO(fd_set *set)
void FD_SET(int fd,fd_set *set)
int FD_ISSET(int fd,fd_set set)
void FD_CLEAR(int fd,fd_set
set)

优点:可以跨平台,移植性好,
缺点:监控的描述符有数量限制 FD_SETSIZE默认1024个;每次都需要向集合添加描述符,并拷贝到内核,(每次监控会修改集合);
监控原理:轮询遍历(超时,描述符就绪触发)性能会随着描述符增多下降;监控调用返回,需要遍历判断哪个描述符在集合中,才能确定哪个描述符就绪

poll 操作流程:

1.用户定义描述符事件结构数组,将需要监控的描述符组织事件信息进行添加
struct pollfd 文件描述符,需要监控的事件,返回的事件(就绪事件)
2.发起监控调用,开始监控
int poll(struct pollfd *fds,nfds_t nfds,int timeout)
fds 描述符事件结构体数组首地址
nfds 数组中有效事件个数
返回值:成功返回事件个数,失败返回-1

3.监控调用返回后,遍历所监控的描述符事件结构体数组,通过节点中的revents成员确定,当前节点的描述符确定了哪些事件,进而对其进行操作

poll优缺点分析:
优点:所监控的描述符数量没有上限;通过事件结构简化了多种集合的操作流程,并且不需要每次监控重新添加描述符
缺点:跨平台移植性差—类unix平台
监控原理依然是将数据拷贝到内核轮训遍历,随描述符数量增多,性能下降
监控调用返回后需要遍历判断每个节点的revents成员,确定当前描述符就绪了哪个事件

epoll操作流程:

sys/epoll.h
1.创建epoll句柄
int epoll_create(int size)
成功返回epoll操作句柄,失败返回-1
2.向内核添加要监控的事件描述符(只添加一次)
int epoll_ctl(int epfd,int op,int fd,struct epoll_event *event)
epfd epoll_create返回的操作句柄
op:要进行的操作 EPOLL_CTL_ADD/EPOLL_CTL_DEL/EPOLL_CTK_MOD
fd:要监控事件的描述符
event:针对要监控描述符所组织的事件结构
3.发起调用开始监控
int epoll_wait(int epfd,struct epoll_event *events,int maxevents,int timeout)
//操作句柄,epoll_event 事件结构体数组首地址–获取就绪事件,第二个参数event数组的节点数量,时间,返回值:成功就绪事件的个数,0超时,失败-1
异步监控,监控任务交给系统完成,系统针对每一个描述符的就绪事件作出回调,回调处理中,是将就绪的描述符对应的事件信息,向双向链表中拷贝了一份,并修改了events成员为实际就绪事件
对于当前进程,调用了epoll_wait 接口之后,只是判断rdllist链表是否为空,如果有数据就是存在就绪事件,将链表中的信息拷贝至epoll_wait传入的数组中进行返回(events数组)
4. epoll_wait调用返回后
只需要根据返回值,遍历events数组,就可以对就绪的描述符直接操作

epoll优缺点分析:

优点:
1.描述符数量没有上限
2. 只需要向内核拷贝一次
3. 监控原理是异步阻塞,监控任务交给系统,进程只判断双向链表是否为空就可以确认是否有描述符就绪,性能不会随着描述符的增多而下降
4. 直接返回的都是就绪的描述事件,直接对就绪的描述符进行操作,不需要用户进行空遍历
缺点:跨平台 移植性差

epoll的事件触发方式:

水平触发:(select 和poll默认水平触发)
可读;只要缓冲区中有数据就会触发事件
可写:只要缓冲区中有空余空间就会触发事件
边缘触发:
可读:只有新数据到来的时候才会触发事件
可写:只有从不可写变为可写,触发一次事件
边缘触发要求尽可能在一次事件触发中处理完毕,可以提高效率,避免事件频繁触发

多路转接IO总结

多路转接IO:
对大量描述符进行事件监控
作用:对就绪的描述符进行操作,避免阻塞,并且提高处理效率
适用场景:对描述符有事件监控的请求,或者超时控制
常被用于高并发服务器的事件触发,
适用于有大量描述符需要监控,但同一时间只有少量描述符活跃的场景,或者对描述符的IO超时控制的场景

多路转接模型与线程池的对比

多路转接模型:用于实现并发服务器,针对就绪轮询处理
线程池:用于并发服务器–基于操作系统的调度轮询,缺点是有可能线程池中的线程,处于空等待状态,
因此:在并发服务器中,多路转接模型和线程池通常搭配使用,采用多路转接模型进行事件监控,有描述符就绪,则抛入线程池中进行处理。例如:事件器模式 设计模式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值