Linux的五种I/O模型

Linux下共有阻塞I/O、非阻塞I/O、I/O复用、信号驱动I/O、异步I/O这五种I/O模型,其中,前四种称为同步I/O。在了解这五种I/O之前,需要先明确同步/异步,阻塞/非阻塞等几个概念。

一、同步、异步、阻塞、非阻塞的概念

同步与异步

同步和异步关注的是消息通信机制。
所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。如果一旦返回,就是得到返回值了。比如,调用readfrom系统调用时,必须等到IO操作完成才返回,此即为同步调用。

所谓异步,就是在调用发出后,这个调用直接返回。换句话说,当一个异步调用发生后,调用者不会立刻得到结果。而是在调用发出后,在条件满足时,再由被调者通过信号或回调通知调用者处理该结果。比如:调用aio_read系统调用时,不必等IO操作完成就直接返回,调用结果通过信号来通知调用者。

举个通俗的例子:
你打电话问书店老板有没有《UNIX环境高级编程》这本书,如果是同步通信机制,老板会说,你稍等,“我查一下”,然后他就开始查啊查,等查好了(可能是5秒,也可能是一天)告诉你结果(返回结果)。
而异步通信机制,书店老板直接告诉你我查一下啊,查好了打电话告诉你,然后直接挂了电话(不返回结果)。然后查好了,他会主动打电话给你。在这里老板通过“回电”这种方式来回调。

阻塞与非阻塞

阻塞和非阻塞,关注的是程序在等待调用结果(消息,返回值)时的状态。
阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
非阻塞调用,指在不能立刻得到结果之前,该调用不会阻塞当前线程。

还是上面的例子:
你打电话给书店老板问有没有《UNIX环境高级编程》这本书,你如果是阻塞式调用,你会一直把自己“挂起”,直到得到这边书有没有的结果;如果是非阻塞调用,你不管老板有没有告诉你,你自己先一边去玩了,当然你也要偶尔过几分钟check一下老板有没有返回结果。
在这里阻塞与非阻塞与是否同步异步无关。跟老板通过什么方式回答你结果无关。

二、Linux下的五大经典I/O模型

阻塞I/O

在Linux用户进程读取数据的时候,需要经历两个阶段:
(1)等待数据就绪
(2)读取数据
如果用户进程尝试读取数据,而数据尚未到达内核空间,或者已到达内核缓冲区,但还未拷贝到用户空间,这时用户进程无法读取到数据,就会进入阻塞。

非阻塞I/O

在非阻塞I/O种,如果进程未获取到数据,此时进程会立即返回结果,而不是阻塞在原处。
这里会涉及两个阶段:
阶段一:
用户进程尝试读取数据,可是数据尚未达到(未准备好)此时内核是处于等待状态;但是由于是非阻塞IO,此时用户会返回异常,即用户进程并不会阻塞等待;①用户进程拿到error后,再次尝试读取,①循环往复,直到数据就绪。
整个过程和CPU的轮询很是相似。
阶段二:
此时数据已经到达并来到了内核缓冲区,代表已经就绪;但是数据还只是在内核空间中,并没有被拷贝到用户空间中,所以这时候用户进程还是不能处理数据,继续阻塞。
直到数据拷贝到用户空间中,用户进程才解除阻塞,开始处理数据。

I/O多路复用

I/O多路复用常用于socket编程中,是利用单个线程同时来监听多个FD,并在某个FD可读、可写时得到通知,避免无效的等待,充分利用CPU资源。常用的IO多路复用有以下几种:
(1)select
(2)poll
(3)epoll
其原理和实现不赘述。

信号驱动I/O

信号驱动IO是与内核建立SIGIO的信号关联并设置回调,当内核有FD就绪时,会发出SIGIO信号通知用户,期间用户应用可以执行其它业务,无需阻塞等待。
阶段一:
①用户进程调用sigaction,注册信号处理函数
②内核返回成功,开始监听FD
③用户进程不阻塞等待,可以执行其它业务
④当内核数据就绪后,回调用户进程的SIGIO处理函数
阶段二:
①收到SIGIO回调信号
②调用recvfrom,读取
③内核将数据拷贝到用户空间
④用户进程处理数据
信号驱动I/O存在较为明显的缺点,当有大量IO操作时,信号较多,SIGIO处理函数不能及时处理可能导致信号队列溢出,而且内核空间与用户空间的频繁信号交互性能也较低。

异步I/O

异步IO的整个过程都是非阻塞的,用户进程调用完异步API后就可以去做其它事情,内核等待数据就绪并拷贝到用户空间后才会递交信号,通知用户进程。(这个过程就像是CPU的中断机制一样,用户进程把任务放出去后,就可以去干其他事情了,待内核处理完毕后,内核会给信号用户进程)
这里需要区别一下的是,异步IO和信号驱动IO都有点像是中断模式,但是两者的区别是,信号驱动IO在第一阶段结束的时候就发出中断信号了,第二阶段需要用户进程参与;而异步IO则实现了真正的异步,内核只有把所有东西都处理完了(数据都拷贝回到用户空间了)才会发出中断信号

阶段一:
①用户进程调用aio_read,创建信号回调函数
②内核等待数据就绪
③用户进程无需阻塞,可以做任何事情
阶段二:
①内核数据就绪
②内核数据拷贝到用户缓冲区
③拷贝完成,内核递交信号触发aio_read中的回调函数
④用户进程处理数据

异步IO的缺点是在高并发场景下,因为IO效率较低,所以会积累很多任务在系统中,容易导致系统崩溃(可以用限流等方式解决,但是实现方式繁琐复杂)。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值