关于io多路复用的理解

0. 一个小故事

需求:小黄是一个收信员,需要去A,B两家收信。他先去了A, 但A磨磨唧唧的就不给小黄信,小黄只能干等着,而B的信早就写好了一直等小黄来收,但是由于小黄只能等A给信了才能再去B收,结果让B等了几个小时。最后,小黄被生气的B投诉扣工资。

bio :经过上次的教训,小黄决定为每个客户都安排一个收信员1对1服务,这样虽然投入增加了,但是每个客户都非常满意。于是小黄的客户越来越多,可是随着客户增加,小黄发现收信员也越来越多,渐渐入不敷出。而且,很多收信员根本不忙,大部分时间都在等着客户写信,于是小黄决心优化收信的流程。

io多路复用 : 这次,小黄辞退了所有收信员,自己一个人收信,只不过,这次他不再等客户写完信再走了,而是给客户留了个电话,告诉客户说:如果你写好了信,就给我发短信,我就过来取信。之后小黄每天只要不停的盯着手机看,只要有短信通知,就立马过去收件,一个人就服务了所有客户

1. bio的一些背景

1.1 数据读取的两个阶段

对我们用户来说,当调用read从硬盘里读取一个文件时,我们会认为是直接从硬盘里把数据读取进内存的,其实不是这样,数据的读取分为以下两个阶段:

  1. 数据准备阶段(写信):把数据从硬件(例如硬盘,网卡)读取到内核缓冲区(不需要内核参与)
  2. 数据传输阶段(收信):把数据从内核缓冲区复制到进程缓冲区(内核参与)

1.2 bio是怎么阻塞的

前面我们提到,数据的读取有两个阶段,bio的阻塞,其实发生在第一个阶段,让我们列一个简单的读取过程

  • 用户发起一个read系统调用
  • 检查内核缓冲区有没有想要的数据,此时有两种情况.
    • 内核缓冲区有数据,那么内核就直接把数据从内核缓冲区复制到调用read方法的线程缓冲区,不阻塞线程(如果信已经写好了,就直接取走)
    • 内核缓冲区没有数据,那么内核先挂起线程,然后通过dma去把数据从硬件读到内核缓冲区(不需要内核去参与,此时内核就干别的去了),当数据全部读取到内核缓冲区后,内核唤醒再线程,然后再把数据拷贝到线程缓冲区(如果信没写好,客户当场写信,收信员在旁边等着信写完)

可以从上面的过程中看到,阻塞,其实就发生在硬件到内核缓冲区这一步

1.3 bio的缺点

缺点:每个连接都需要一个线程去处理

从开头的小故事就能了解,为了服务好每个客户,小黄为每个客户都一定要配置一个专属收信员去服务,但是客户人一多,收信员也就多了,成本就高了

2.io多路复用

简单过程

nio模式下,基本流程如下

  1. 收信员(线程)只有一个,但是收信员多了个工具:手机短信(select,poll,epoll)。
  2. 小黄告诉客户,如果信写好了就给自己发短信(将io注册到select上),然后就溜了去下一家继续通知(数据准备阶段不阻塞了!)
  3. 当通知完所有客户要发短信后,小黄一整天都盯着手机,看是否有人给自己发短信(不断轮询select去看是否有注册的io状态就绪)
  4. 如果有人发短信了,就跑去他那取(如果某io状态就绪,这个线程就去取数据)

io多路复用的一些解惑

在刚看io多路复用时,我有些疑惑,记录下来

问题1: io多路复用为什么是非阻塞的?
答:前面已经提到过了,io其实分为两步:数据准备阶段和数据传输阶段。数据传输阶段要内核参与的,所以无论如何也会阻塞住,而非阻塞,指的就是数据准备阶段不阻塞。由于io多路复用在得知内核缓冲区没有数据后会直接返回,所以不会阻塞线程。
问题2: io多路复用的用途?
答:一开始我也没想通,比如我要读一个文件,就算你在数据准备阶段返回了,我又能干啥呢,我还不是要等文件都读到线程内存了才进行下一步,而且就算我同时读n个文件,我还不是要开n个线程去分别处理,因为我们对每个文件对处理方式很多时候是不一样的。后来理解了,io多路复用多用于socket编程,用于服务端处理长连接。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值