【Linux】五种IO模型
什么是IO?
IO就是输入和输出,在冯诺依曼体系结构中,当数据从输入设备拷贝到内存就叫做输入,将数据从内存拷贝到输出设备就是输出
对文件的读写操作本质就是一种IO,文件IO对应的外设就是磁盘
对网络进行的读写操作本质也是一种IO,网络IO对应的外设就是网卡
操作系统如何得知有数据可读取?
输入就是操作系统把数据从外设拷贝进内存的过程,操作系统一定通过某种方法得知特定外设上是否有数据就绪
并不是操作系统要读取时,外设一定有数据
操作系统不会主动去检测外设上是否有数据就绪,这种做法会降低操作系统的效率,因为大部分时间外设是没有数据的,影响操作系统的正常工作
操作系统内部采用中断的方式来进行与外设交互,当外设有数据到来时,该外设就会向CPU中的中断控制器发送中断信号,中断控制器再根据产生的中断信号的优先级按顺序发送给CPU
每一个中断信号都设有特定的中断处理程序-——》中断向量表,当CPU收到某个中断信号就会自动停止正在运行的程序,然后执行对应的中断程序,处理完毕再返回被暂停的程序继续执行
虽然外设数据不可以直接与CPU打交道,但是外设可以通过某种方式把控制信号发送给CPU
操作系统如何从网卡中读取数据包?
操作系统每时每刻都可能有大量的数据包要接收,因此操作系统必须把这些数据包管理起来,通过结构体的方式,每一个数据包就是一个结构体类型
当操作系统从网卡中读取到一个数据包后,会把该数据依次交给数据链路层,网络层,传输层,应用层进行解包处理,最后交给用户,这里所谓的解包其实是指针的移动
什么是高效的IO?
IO主要分两步
第一步是等,等待IO条件就绪
第二步是拷贝,就绪后把数据拷贝到内存或者外设
任何的IO都涉及到等和拷贝的过程,而实际情况中等的时间远远大于拷贝的时间,所以要尽量减少等的时间,才是高效IO(减少等)
五种IO模型举例说明
钓鱼5人组
张三:钓鱼,一直等着,什么也不做,只等鱼上钩
李四:鱼竿抛入水中就不管了,定期查看一下有没有鱼上钩,有则钓上来,没有则做其他事情
王五:鱼竿上绑了一个铃铛,鱼竿抛入水中就不管了,有鱼上钩铃铛响了再回来钓上来
赵六:拿了100个鱼竿,把100个鱼竿同时抛入水中,观察所有的鱼竿,有鱼上钩就钓上来,没有则继续观察
田七:田七雇了一个人,让他去钓鱼,钓完鱼给他就行
这就是五种IO模型,他们的效率有什么不同吗?这里说的效率是IO互相流动的效率
本质上,张三 李四 王五的效率都是一样的,他们等的方式不同,但是鱼上钩的几率一样,等的时间一样
赵六则不同,鱼上钩的几率是他们三个的100倍
高效的IO是减少等的时间,增加拷贝的时间,所以赵六的效率是最高的
田七呢?
田七属于异步IO,交给其他人去做
张三:阻塞IO 一直等待就绪
李四:非阻塞IO 定时检测
王五:信号驱动IO 通知就绪
赵六:多路复用IO 同时等待多个就绪
田七:异步IO 交给其他人去做
这里我们可以了解到,前4种 阻塞 非阻塞 信号驱动 是无法提高IO的效率的,但是非阻塞和信号驱动能提升整体做事的效率,因为等的同时可能做其他事情
阻塞IO--》等待就绪,否则卡住
比如read读取时,没数据阻塞
非阻塞IO--》不等待就绪
设置read非阻塞,轮询读取
信号驱动IO--》好了通知拿数据
捕捉信号,设置处理函数read,好了再read
多路复用IO--》同时等待多个
select \ poll \ epoll 三种方式实现
异步IO--》交给别人做
通过一些特定IO接口实现,内核帮忙处理
高级IO重要概念
同步 / 异步
同步和异步就是消息通信机制的方式
所谓的同步就是调用者需要主动等待调用的结果
所谓的异步则是调用者调用后直接返回,无需关注调用结果,结果完成通知调用者即可
阻塞IO的实现:
此时没有数据read阻塞
非阻塞IO的实现:
先通过接口设置文件描述符为非阻塞,没有就绪则返回 轮询查询
再通过read读取,此时read读取没有数据则直接返回,继续下一步操作等待下次循环