同步?异步?阻塞?非阻塞?多路复用?
写在前面
无论是在你看各种中间件在IO方面的优化,还是在各种面试题中,IO模型都是占了举足轻重的地位。然而,什么同步阻塞,同步非阻塞,异步阻塞,异步非阻塞等等,都会让你晕头转向。当你Google这些区别,你总能查到各种各样的生活中的例子来帮助你理解,那一刻你懂了,但是回过头来好像又觉得差了点意思。
在这一篇文章中,我们以 《UNIX网络编程:卷一》第六章 的说法,来看看各种IO模型的本质是什么。
在阅读这一篇文章之前, 你需要了解的前置知识点有:
- 了解Socket与文件描述符的关系
- 了解进程的五状态模型
- 了解用户态与内核态的区别
为了文章的连贯性,本文就不对这些前置知识点做过多的解释了。如果在阅读过程中你产生了一些疑问,可以先看完文章,然后再去详细的了解这些知识点。
1.IO的流程
在区分各种IO模型的区别之前,我们需要先了解一个IO,在操作系统的层面究竟发生了哪些事情。注意,我们说的IO模型对IO的优化,都是基于读IO。
假设我们需要等待Socket的数据,也就是说当前是一个读操作的IO,那么在操作系统层面需要分为两步:
- 等待数据被写入Socket的缓冲区中
- 将Socket缓冲区中的数据拷贝到应用程序中
我们可以很容易的发现,第一步是由对方决定的,对方决定了什么时候把数据发送过来。第二步是由操作系统决定的,操作系统需要陷入内核态拷贝数据。
而我们的同步异步、阻塞非阻塞也是从这里出发的。
这里先提一下,阻塞和非阻塞指的是第一个阶段,进程等待缓冲区被写入数据的方式;同步和异步指的是第二个阶段,进程需不需要等待操作系统把数据从缓冲区拷贝到应用中。
2.五种IO模型
2.1 阻塞
在同步阻塞的IO模型中,在第一阶段“等待数据被写入Socket的缓冲区中”,操作系统会把当前的进程设置为阻塞状态,直到缓冲区被写入数据这个进程才被唤醒。
这也就造成了一个问题,当操作系统把这个进程置为阻塞态的时候,这个进程就什么事都做不了了。
2.2 非阻塞
为了解决“同步阻塞”进程可能无期限阻塞的情况,于是产生了“同步非阻塞”
在这种IO模型中,如果发现这个Socket里面没有准备好的数据就返回一个错误,而不是把这个进程设置为阻塞状态。
也就是说我们可以轮询这个Socket查看有无准备好的数据。
2.3 多路复用
假设此时我们的服务器需要管理很多的IO请求,如果给每一个IO都分配一个进程/线程,自旋的等待有无数据到来,无疑是很浪费资源的。
如果我们用一个进程,轮询所有的IO请求,又会使IO的响应变得很慢。
因此,产生了多路复用IO。
多路复用IO就是用一条线程,同时监听多个IO请求,并且在有IO请求产生的时候返回。
注意,虽然我们的IO多路复用也会阻塞,但是这里的阻塞是应用层面的,也就是说在多路复用的方法上进行阻塞,而不是在操作系统层面去阻塞。
2.4 信号驱动
在以上的IO模型中,都是需要应用自己去“询问”Socket是否已经准备好了数据,而信号驱动就是由Socket“主动”告诉你有没有准备好数据。
这么做的好处在于第一阶段程序不需要任何的等待与轮询,只需要在收到了信号通知之后去处理这个IO即可。
2.5 异步IO
在以上的四种IO操作中,无论第一个阶段是如何进行优化的,在第二阶段都需要陷入内核态来拷贝数据。
异步IO就是为了解决这个问题。
异步IO在解决了阻塞这个问题后,同样把陷入内核态来拷贝数据的时间也节省了。
这样,当程序需要进行IO的时候,只需要发出IO的请求,然后就可以继续执行后面的代码,直到IO完成操作系统会通知程序。
同样的,异步IO是非阻塞的。
3.总结
到了这里,我想你应该可以分别各种IO模型了,无论是同步阻塞,还是同步非阻塞...不会被这些模型搞的一脸懵逼,记了忘忘了记。
只需要记住阻塞跟非阻塞,是在等待数据这个阶段的;同步跟非同步,指的是需不需要等待CPU进行数据的拷贝。
写在最后
首先,谢谢你能看到这里,新年快乐!
我拖更了好久好久了,前段时间因为自己没能调整好时间,在这里跟大家说声抱歉。
在过去的半年,我们比较粗粒度的学了一遍作为一个开发应该掌握的各种基本技能,基本都是各种《XXX入门》,属于技能广度上的扫盲。
在接下来的半年中,我的小目标就是能够在技术深度上有一定的进步,也同样希望我能够把复杂的东西讲得更清晰明了。
(这应该是新年的第一个flag了hhh)
我初步的计划是先把gRPC研究的稍微深入一些,而不是停留在如何调用各种API。也希望可以站在一个更高一点的层面来分析gRPC,了解gRPC为什么要这么设计,而不是逐行加上注释来解释gRPC是怎么实现的。
这是一个新的尝试,会有点难,不过,我们一起努力吧!
在这个过程中,有任何问题你都可以在公众号搜索“红鸡菌”找到我,我也同样很希望得到你的反馈,包括但不限于“我哪里写的不明白”,“你希望看到什么样的内容”等。
再次谢谢你能看到这里!
2021一起加油~