【操作系统】高级IO

典型常见的IO模型

IO的过程:等待+数据拷贝(socket接收数据,首选socket接收缓冲区中得有数据,如果没有数据,则需要等待,有了就将数据拷贝出来)

1、阻塞IO

发起IO调用,若不满足IO条件,则等待。

在这里插入图片描述
优点:流程清晰简单,一个完成之后才能进行下一个

缺点:IO未就绪一直等待,资源利用率太低,IO效率太低
 

2、非阻塞IO

发起IO调用,若不满足IO条件,则调用立即报错返回。
在这里插入图片描述
优点:相较于阻塞IO,更能充分利用资源,效率高一点,一个IO未就绪就可以尝试下一个IO

缺点:需要循环操作,流程相对比较复杂,并且实时性不高(有可能IO就绪很长时间,才循环回来进行第二次IO操作)。

 

3、信号驱动IO

首先定义IO就绪信号自定义处理函数,如果收到IO就绪信号,则在回调函数中进行IO操作。
在这里插入图片描述
优点:相较于非阻塞,IO实时性更高,IO效率也更高(收到信号,IO就绪就再去发起IO)

缺点:需要自定义信号处理,流程更加复杂(IO流程已经不再固定)
 

4、异步IO

首先定义IO完成信号自定义处理,如果IO完成信号,则直接在回调函数中处理数据。

前面几种不管流程如果,都是进程自身完成IO操作,而异步IO,指的是IO操作由系统完成。

在这里插入图片描述
当发起IO调用的时候,会告诉操作系统,要对那个描述符进行IO操作,以及就绪后拷贝数据应该放在哪里,以及拷贝多少数据。

这几种IO模型,效率越来越高,但是流程越来越复杂。

异步IO:发起IO调用,由别人完成IO,收到信号则表示IO已经完成。

优点:对系统的资源利用最充分,IO效率也最高。

缺点:流程最为复杂。
 
阻塞和非阻塞的区别:一个功能函数,在无法完成功能的情况下是否立即返回。

同步与异步的区别:任务是否由自己完成,完成的流程是不是顺序的。

  • 同步与异步没有谁好谁坏,只谈论适合的场景
  • 同步:流程简单,效率较低;异步:流程复杂,占用资源多,效率更高
  • 同步同一时间只能进行一个IO,只需要申请一个buff获取数据,占用资源少,一个完成了进行下一个,流程简单
  • 异步非阻塞可以循环发起多个IO,就需要申请多个buff获取数据,占用资源多,流程不固定,较为复杂
  • 工作中,项目进行了大量的IO操作,通常编写同步代码是否能够达到性能标准;若无法达标,尽量使用异步操作
     

多路转接IO模型

目的:对大量的描述符进行就绪时间监控,能够让程序员对就绪的描述符进行操作(避免对没有就绪的描述符操作,造成阻塞或者性能降低)

示例:以tcp服务端socket为例,一个任务流程中既有后去新连接,又有与每个客户进行通信,任意一个操作有可能在未就绪的情况下导致流程阻塞,要是能够仅仅针对就绪的描述符进行操作,就不会阻塞了。

实现:三种实现模型----select、poll、epoll
 

5、select

5.1 select实现流程

1)程序员定义指定事件的描述符集合(三种事件对应三个集合),初始化清空集合,将要监控指定事件的描述符添加到指定的集合中

2)发起监控调用,将三个描述符集合拷贝到内核中进行监控,若有描述符就绪了,或者监控等待超时,则监控调用返回,在返回之前将三个集合中没有就绪的描述符从集合中移除(也就意味着返回的集合中都是就绪的描述符)

3)逐个判断描述符是否还在集合中,就知道那个描述符继续了,进而执行对应操作

 

5.2 select优缺点分析

优点

  • 遵循POSIX标准,跨平台移植性强
  • 监控的超时等待时间可以精细到微妙

缺点

  • select所能监控的描述符有最大的上限----取决于宏__FD_SETSIZE,默认是1024
  • select监控原理是将集合拷贝到内核,进行轮询遍历监控性能会随着描述增多而下降
  • select监控返回时,会从集合中移除未就绪的描述符,因此没监控都需要重新向集合添加描述符
  • select监控不会直接返回描述符,而是就绪的比特位图,需要用户遍历判断哪个描述符在集合中才能确定是否就绪事件
  • 每次监控,都需要重新添加,也就意味着每次监控时都要将集合从用户态拷贝到内核态

 

6、poll

poll优缺点分析

优点

  • 监控的描述符没有上限
  • 采用事件结构的方式监控,简化了多种集合的操作流程

缺点

  • 无法跨平台
  • 需要每次将事件结构信息拷贝到内核
  • 监控原理也是将轮询遍历,性能会随着描述符增多而下降
  • 同样不会返回就绪的描述符,需要程序员进行遍历判断每个节点revent成员才能确定就绪的事件

 

7、epoll

7.1 epoll操作流程

1)通过epoll_create在内核中创建eventpoll结构体句柄

2)通过epoll_ctl向内核指定的eventpoll结构体中的红黑树添加成员要监控的描述符以及时间结构体信息

3)通过epoll_wait开始监控,有描述符就绪或者等待超时则监控调用返回;返回时,就绪的描述符对应事件结构会通过接口参数返回

4)程序员遍历evs数组,逐个进行操作(evs数组中的节点都是就绪的描述符事件结构)

7.2 监控原理

epoll的监控是一个异步操作;发起epoll_wait开始监控,只是告诉系统开始监控,监控过程由系统完成;系统为每个描述符的就绪事件设置了回调函数,当描述符就绪时,则调用回调函数,直接将描述符对应的事件结构添加到eventpoll中的双向链表中。进程会每隔一段时间看下,内核中的eventpoll的双向链表中是否为NULL,确定没有描述符就绪

 

7.3 LT和ET

1)epoll的水平出发模式:EPOLLLT(默认的触发方式)

  • 可读事件:只要接收缓冲区的大小大于低水位标记
  • 可写事件:只要发送缓冲区的剩余空间大小大于低水位标记
  • 低水位标记:判断的基准值,默认是一个字节

2)epoll的边缘触发模式:EOPLLET

  • 可读事件:只有接收缓冲区有新数据到来才会触发事件
  • 可写事件:只有发送缓冲区剩余空间从无到有才会触发事件

 
3)边缘触发的场景:当接收数据的时候,发现数据不完整

  • 把数据取出来,在外部进行一个缓冲区的维护
  • 放到缓冲区中,等待新数据到来的时候,重新接数据

 
4)边缘触发的注意事项
当有新数据的时候才会触发事件,如果不进行第二次读取数据,那么我们就无法将数据完全读完,因此我们最好一次将数据从缓冲区中读完。

如何将数据一次读完?
缓冲区当中的数据我们不知道有多少,所以采用循环的方式读取数据,recv默认采用阻塞的方式,因此必须采用非阻塞操作。如果采用阻塞操作,就会导致缓冲区中没有数据的话,一直阻塞在循环中。

5)epoll的优缺点分析

缺点

  • 无法跨平台,移植性差

优点

  • 监控的描述符没有上限
  • 描述符的监控信息,只需要向内核添加一次
  • 监控原理是异步阻塞操作,由系统监控,进程判断就绪链表是否为空确定是否有就绪,性能不会随着描述符增多而下降
  • 直接向程序员返回继续的描述符事件信息,程序员可以直接针对就绪的描述符进行操作,而不需要进行空遍历
7.4 多路转接模型的应用场景

考虑跨平台移植,使用select;不考虑移植性,则使用epoll。

大量的描述符需要监控,但是同一时间只有少量活跃的场景。如果有大量的描述符活跃,会导致并发轮询处理的速度较慢,反而不如多执行流的并发/并行处理。

大多数情况下,多路转接模型可以与多执行流模式搭配使用,使用多路转接模型进行大量的描述符的事件监控,有描述符就绪,则抛入线程池中进行多执行流处理(防止放入线程池,但是长时间不发送数据空浪费线程) ----reactor-事件器模式

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值