初识五种IO模型

以下内容均为本人学习笔记,若有不当,感谢指出

我们将IO分为两步,第一步为等待,第二步为数据搬迁

  • 而往往是等待的过程限制了IO的执行效率,针对这个性能瓶颈,只要我们能降低IO中等待的比重,就能提高IO效率
  • 下面讨论将针对如何降低IO中等待的比重来提高效率

下面是人们为解决行IO效率提出的五种IO模型

五种IO模型

1.阻塞IO

在内核将数据准备好之前,系统调用会一直等待,所有的套接字都是阻塞式的
阻塞IO是最常见的IO模型

阻塞式IO在系统调用未返回时,进程会一直阻塞,在这期间什么事也做不了,时间资源浪费,效率太低。

初识五种IO模型

图1 阻塞式IO

2.非阻塞式IO

如果内核还未将数据准备好,调用仍旧会直接返回,并返回EWOULDBLOCK错误码
当然调用可以返回是基于非阻塞文件描述符

非阻塞式IO数据还没有准备好时,并不会挂起,会执行其他任务,期间需要反复尝试读取文件描述符状态,这个过程一般需要程序员自己实现循环尝试读取文件描述符,也这种过程称为轮询
但是这种做法也有它的缺陷

  • 轮询时间不好控制
  • 代码编写较复杂
  • 轮询过程对CPU资源浪费较大

3.信号驱动IO

内核将数据准备好之后,发送SIGIO信号通知应用进程进行IO操作

信号驱动IO模型,注册信号捕捉SIGIO信号,信号到来才调用recvfrom。这里的recvfrom只进行数据准备。避免了上面阻塞IO轮询式对CPU资源的浪费,而是采用信号通知的方法得知文件描述符状态。但是也存在自己的问题:

  • 在多线程程序中,同组线程之间共享信号集,若收到一个信号,所有信号都将挂起等待,只有到信号处理完成后,才可能正常执行

4.IO多路转接

类似于阻塞式IO,核心在于一个线程同时等待多个描述符状态

调用select等待多个文件描述符,recvfrom只是select返回后进行数据拷贝。
多路转接IO模型,因为可以批量等待,在等待文件描述符就绪的概率明显提高,多路转接IO模型也是效率最高效的,这种IO模型也是重点讨论的
初识五种IO模型

图2 多路转接IO

上面4中IO模型都是调用者自己等待结果状态,我们称为同步IO

5.异步IO

内核在数据拷贝完成时通知应用程序(而信号驱动是以信号机制告知程序何使可以开始拷贝数据)

概念补充:
(1) 阻塞IO和非阻塞IO
这里的阻塞和非阻塞关注的是程序在等待调用结果时的状态

  • 阻塞调用:调用结果返回之前,进程一直被挂起,只有得到调用结果才会返回
  • 非阻塞调用:没有得到调用结果之前,该调用不会阻塞进程

(2)同步通信和异步通信

这里的同步和异步关注的是消息通知机制,应该与同步互斥中的同步区分开

  • 同步 : 没有得到调用结果之前,该调用就不返回,一旦调用返回,就得到返回值,调用者主动等待调用状态。
  • 异步 : 调用发出之后,这个调用就返回了,没有返回结果;调用者不会立刻得到结果,由被调用者通过状态、通知来通知调用者,或者通过回调函数处理这个调用。

实际应用中同步异步的应用

同步的思想是:

服务器将所有的操作都完成了,才将结果返回给客户。
例如说,处理用户注册账号的请求,服务器开始处理用户提交的数据,将用户的信息插入数据库,这些操作都执行完成后,才给用户返回一个注册成功的提示,那在服务器处理业务的这段时间内,客户端界面就不动了。处于一种类似于卡死的状态,只是因为请求正在处理,暂时没有响应而已。
此时用户端不能关闭界面,如果关闭了,迁移程序就终止, 那么执行就中断了。

这样的话不仅服务器压力大,用户体验还不好。

异步的思想是:

服务器尽快将结果返回给用户,再进行处理用户的数据
还是注册的例子,服务器将用户的请求放在消息队列中,然后向用户反馈已经成功了消息,系统迁移程序已经启动了,你可以进行别的操作,也可以关闭浏览器了。
然后服务器端再将用户的数据写入数据库,这就是异步的思想。

用户能在很快的时间内收到响应,对用户来体验是很重要的。

同步异步操作的场景:

异步我们通常是采用一种缓存机制,一般使用消息队列来完成,先将数据放入消息队列中,然后再执行写入数据库的操作
因为异步操作效率比较高,所以项目中一般都会采用异步机制
但是在一些多线程读写共享资源时就应该采用同步机制了,银行转账系统、购票系统、数据库的写操作(事务)等

我能回想起的同步和异步的应用

自己项目中数据库的操作现在暂时还是同步的处理,待完善
之前写的爬虫项目也遇到中ajax异步加载页面,需要再次找到异步加载的资源再进行爬取分析
那记得模电数电中了的同步电路和异步电路的概念,触发器呀和锁存器呀什么的(回忆不起来了)。

完。