一文搞懂IO模型

概述

相信大家都喝过奶茶吧,奶茶还是很好喝的!

去奶茶店买奶茶一般是这样的流程:

  1. 有顾客上门
  2. 奶茶店员工点单
  3. 奶茶店员工制作奶茶
  4. 奶茶店员工打包
  5. 顾客取走成品

一个顾客类比一个 I O 连接 一个顾客类比一个IO连接 一个顾客类比一个IO连接

一个员工类比一个线程 一个员工类比一个线程 一个员工类比一个线程


阻塞IO

阻塞IO:所有的IO操作,例如发送、接收等,都需要阻塞等待,等一个操作执行结束,才能执行下一个。

单线程阻塞IO

你开了一个奶茶店,自己积蓄全都投入了。现在,你一肩挑,负责店里所有的事情:点单、责奶茶制作、打包、通知顾客取餐。

闲着时,有客人上门,可以马上为他服务。但如果你在忙,就算有新的客人上门,也得候着,你只能口头关照一下。

你 = 一个线程 你 = 一个线程 =一个线程

单线程阻塞 IO 定义:一个线程处理所有客户端连接,如果线程忙碌,那需要等当前连接完成,才刻意处理下一个连接。

多线程阻塞 IO

奶茶店干了一段时间后,生意越来越好了。作为老板的你招聘了 3 个员工作为帮手。这样就可以有 4 个人同时服务客户了,赚的钱肯定也是更多啦。

如果碰到节假日,店里的顾客太多,4 个人也忙不过来,还有很多顾客在排队等待,有的客人等的没有耐心了,就直接走掉,不排队了,你痛失了很多流式的客户。

多线程阻塞 IO 定义:来一个连接,就新建一个线程进行处理。不过,如果并发量很大(同时有多个连接),可能会导致内存溢出(OOM),即内存不够用。

有一种处理方法:可以规定最多只能同时处理 10 个连接,这样可以避免内存溢出。不过,当并发连接数达到 100 时,会导致处理速度跟连接数量,即很多连接在排队等待。这种情况恶化的话,还会导致客户端超时。

多线程阻塞 IO 优点

  • 开发相对简单,在操作阻塞时,现成被挂起,不会占用 CPU 资源。

多线程阻塞 IO 缺点

  • 连接的利用率不高,如果系统没有响应数据,会一直处于阻塞状态,占用连接资源。
  • 不适用高并发场景。

非阻塞 IO

作为老板,你发现,一个员工同一时间只能服务一个客人,比较浪费。完全可以先给客人点单,然后去制作奶茶。

客人可以随时问店员,奶茶是否已经制作好了:

  • 如果奶茶还没有制作好,则告知顾客,还需要耐心等待。
  • 如果奶茶已经制作好了,在顾客询问后,可以立马把制作好的奶茶拿给客户。

奶茶店的日均流水得到了进一步提升,作为老板的你当然开心啦!

这种方式,虽然可以提升流水,多多接单,但是需要客人不停的询问。如果有的客人忘记了询问,会浪费客人的时间,让顾客的体验不是很好。

非阻塞 IO 定义: 客户端发起请求后,如果系统还未准备好,就立刻返回错误(告知客户),不让客户端阻塞等待。一旦数据准备好了,再次收到客户端请求时,系统会马上将数据拷贝给客户端。

非阻塞 IO 优点

  • 客户端不会被阻塞,实时性好。

非阻塞 IO 缺点

  • 当客户端没有获取到数据时,会不断询问,占用大量CPU时间,效率不高。

多路复用 IO

作为老板,你又发现,奶茶店可以招聘一个专门的收银员为用户点单,通知其他员工制作奶茶,同时还能照顾客人的情绪,进一步提升门店的购物体验。

  • 收银员为客人点单,一个收银员可以同时服务多个客人。
  • 奶茶制作好之后,收银员主动通知客人取奶茶。这样就不用客人每次去询问,奶茶是否制作好了。
  • 而且其他员工,经过培训后,可以同时为多个客人制作奶茶,提高了奶茶的制作效率。

收银员 = 专门处理连接的线程 收银员 = 专门处理连接的线程 收银员=专门处理连接的线程

其他员工 = I O 线程 其他员工 = IO 线程 其他员工=IO线程

**多路复用IO定义:**有专门的线程(一个或多个线程)负责监控多个客户端连接,当有数据准备就绪后,分配或通知对应地线程,进行相应的操作。

多路复用IO模型,是目前使用最广的 IO 模型。它使得系统不必创建大量的线程,只使用一个或几个线程来监听客户端连接,这样一个或几个线程就可以同时处理成千上万个连接,大大减少了系统的开销。

现在的非常主流的网络通信框架 Netty 也是基于的多路复用机制,来实现的

信号驱动 IO 模型

作为老板,你发现还可以进一步提升用户体验。之前是通过收银员来点单,并使用大声叫喊的方式通知顾客。通过人声叫喊的方式通知客户,可能会导致用户听不到收银员的叫喊,导致一直听不到。

你联系了一家软件公司,让它们帮忙开发一个自主点餐系统,用户到店后,直接通过扫描自助点餐。

当奶茶做好了,员工点击已完成制作,此时会在屏幕上显示哪个订单的奶茶已经制作好了,顾客也可以通过手机查看奶茶的制作进度。

当用户看到奶茶制作好了,需要自己过去取走。

信号驱动 IO 定义: 当用户进程(客户端)发起一个 IO 操作时,系统调用 sigaction 向内核注册一个回调函数,并立即返回,不阻塞客户端;当数据准备好时,内核使用信号(SIGIO)通知回调函数

不过用户进程(客户端)需要将数据从内核空间拷贝到用户空间此时是用户进程(客户端)是阻塞的; 也就是说:应用进程将数据从内核拷贝到用户空间的过程是阻塞等待的,这是信号驱动 IO异步 IO 的本质区别。

异步 IO 模型

现在,你的奶茶店已经很好了,已经超过市场上大部分的奶茶店。不过你还是希望进一步提高顾客的体验,于是你又是独自思考的很久。还真被你想到了一个很好的方案。

之前,顾客需要自己看到奶茶是否已经制作完成,然后自行取奶茶。现在你专门招聘了一名服务员,在顾客区,专门引导客人点餐,并随时观察已经制作完成的订单。

当发现奶茶已经制作完成了,这名服务员会亲手将奶茶贴心的送到顾客手上,让顾客有宾至如归的感觉。你的奶茶店的品质得到了进一步的提升,名气也越来越大,渐渐地变成了知名奶茶店。嘿嘿~~!

异步 IO 模型定义: 客户端只需要向内核发送一个请求,告诉内核它要读取数据后即刻返回;内核收到请求后会建立一个信号联系,当数据准备就绪,内核会主动把数据从内核复制到用户空间(而信号驱动 IO 是告诉应用程序何时可以开始拷贝数据),异步 IO 模型真正的做到了完完全全的非阻塞

Tips:异步 IO 模型其他 IO 模型最大的区别是:前 4 个都是有阻塞的,需要客户端把数据,从内核拷贝到用户空间。而异步 IO 模型用户进程(客户端)完全不需要关心整个 IO 操作是如何进行的,只需发起一个请求,当接收内核的成功信号时,可以直接使用数据,它是最理想的模型。

相关推荐

  1. OPC质量码

    2024-07-19 19:52:06       71 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-19 19:52:06       101 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-19 19:52:06       109 阅读
  3. 在Django里面运行非项目文件

    2024-07-19 19:52:06       87 阅读
  4. Python语言-面向对象

    2024-07-19 19:52:06       96 阅读

热门阅读

  1. 快速上手绿联私有云UGOS Pro系统Docker

    2024-07-19 19:52:06       22 阅读
  2. 跟ChatGPT学习go语言--int 类型如何转化成string

    2024-07-19 19:52:06       20 阅读
  3. C语言相关知识点(不定期更新内容)

    2024-07-19 19:52:06       26 阅读
  4. C++如何管理指针从而避免内存泄露

    2024-07-19 19:52:06       22 阅读
  5. OpenCV——图像与视频的保存

    2024-07-19 19:52:06       20 阅读
  6. Vue 给表格单元格加省略号和hover提示

    2024-07-19 19:52:06       26 阅读
  7. Eclipse Temurin Docker镜像

    2024-07-19 19:52:06       21 阅读
  8. npm 缓存目录

    2024-07-19 19:52:06       17 阅读
  9. vllm安装踩坑

    2024-07-19 19:52:06       24 阅读
  10. 探索Eureka的高级用法:在服务中实现分布式锁

    2024-07-19 19:52:06       20 阅读