我对同步异步、阻塞非阻塞的理解

我对同步异步、阻塞非阻塞的理解

这方面的知识很多人都已经耳熟能详了,但是在今天想要开始入手netty时,我做了进一步的思考,按照网上的说法, 几乎所有的博客都是一样的解释方法,类似于这样:

image-20200615222753313

这样的话,同步就是阻塞,异步就是非阻塞,为什么要发明两套概念呢?说不通啊,很多博客内容再配上各种生动形象的例子,例如老王喝茶水、或者打电话,看过之后就是令人非常满意,但是想要好一点的理解netty,一定要再深一层层次的理清一些概念,下面的内容参考http://www.tianshouzhi.com/api/tutorials/netty/221,并且加入了一些自己的理解。

IO

这个概念更加熟悉,IO的场景主要还是有两种,磁盘IO和网络IO,因为netty主要负责节点之间的通信,而节点之间通信是以套接字为基础,那么这里就说网络IO

五种IO模型

1、阻塞式I/O:blocking IO

2、非阻塞式I/O: nonblocking IO

3、I/O复用(select,poll,epoll...):IO multiplexing

4、信号驱动式I/O(SIGIO):signal driven IO

5、异步I/O(POSIX的aio_系列函数):asynchronous IO

下面以操作系统的角度来说几句:

操作系统分为两个空间,分别是用户空间和内核空间,用户空间是常用进程所在的区域,JVM进行就在这里

内核空间负责系统调用,和用户空间相比多出了很多权限,这样分开的目的就是为了保护,安全,防止用户的进程轻易碰内核,当用户进行执行了一个系统调用,假如说就是read,那么在操作系统一共进行这么两步:

  • 准备数据
  • 将数据从内核复制到进程

这个概念之前就有,所有的系统调用都是直接或者间接通过内核的,明确了这个,就可以说下面的五种IO模型了

1.blocking io

也就是传统的BIO,直接上图:

Image.png

可谓是自从系统调用发出之后,进程就一直处于阻塞状态,第一阶段数据还没准备好,准备好了之后再复制,这之后进程才能恢复非阻塞状态

2.no-blocking io

也就是NIO,

Image.png

我们可以看到,在数据准备阶段,此时内核中数据没准备好,给进程返回一个error,进程收到error之后一直在不断的询问,这时进程是非阻塞的,但是在拷贝阶段,进程还是会阻塞

3.io multiplexing

Image.png

多路复用,也叫事件驱动,好处就是一个进程可以处理多个网络IO,但是这里面要多加一个系统调用select,之前在NIO中进程自己轮询不断的检查状态,有了这个系统调用之后,轮询操作由内核来负责,可以理解为监听,当得知某个socket中有数据到来时,并且数据已经准备好之后,返回一个可读状态,select系统调用被返回,进程进行下一个系统调用read,将数据从内核拷贝到进程中去,其实这个图这么一看和BIO差不多,但是他的特点就是select 系统调用起到了一个选择器的作用,可以实现多路复用,能够处理更多的连接,但是这里涉及到性能比较的问题,虽然可以多路,但是多了一个系统调用,要知道系统调用可基本上是操作系统最耗时的操作,在一些情况下,到底是使用多路复用更好,还是使用多线程+BIO的性能更好,还真说不准。

4.信号驱动式IO

这个用的很少,直接上图,啥也不说了,有他完全是为了完整性

Image.png

5.异步I/O

Image.png

异步IO进程很潇洒,只要发出系统调用就可以去做其他事情了,全程不会发生阻塞,即使是数据复制阶段,但是这里我有一个问题,给进程返回的信号如果是sucess确实很潇洒,但是fail怎么办?重试?一直重试不成功怎么办??后面的事务又需要这部分数据,这???先放在这里,今后一定会遇到


在上面的五种模型中,除了最后一种以外,其他全部是同步的,这里我相信也可以看出同步和阻塞的区别了,BIO是同步的,而且是一直阻塞的,NIO是同步的,虽然在数据准备阶段不会发生阻塞,但是数据复制阶段还是会阻塞,只有异步IO全程不阻塞,多问一句,异步可以阻塞嘛,我觉得可以,但是几乎不会这么搭配,除非脑子被驴踢了

看了网上的很多例子,我也举一个,可能比较粗糙,

同步就是两个事情之间真的是制约的,假如说我在西体跑步,手里面拿着一个手机,我发个微信等待回复,如果是同步,那么我是不会再前进一步的,因为我向前移动和待回复的消息是同步的关系,我必须不能向前,才是同步,但是,我们规定的是不能向前,可是我可以有两种状态,原地站着,或者原地小跑,我在那里一动不动的站着,就是阻塞,我原地踏步跑,就是非阻塞,而异步是什么呢?发出去消息接着跑,等到消息恢复时微信会有提示音的~~~

最后闲聊几句吧,最近在意识上真的意识到了异步这两个字对于系统设计的重要性,对一个系统性能来讲,尤其是高并发系统,同步IO根本是无法忍受的,在之前一篇关于消息队列的文章中,我也是说到了,消息队列的一个很重要作用就是异步,这样连个模块之前才会更加灵活,还有,netty的官方介绍中,netty是一个异步的、事件驱动的网络应用框架,今天算是认识到了Netty的重要性,不管是目前接触到的vertx,还是dubbo,还是elasticsearch,基石啊

好了,就这样,本来今天晚上打算早睡的,但是和飞宇讨论了一道算法题之后整个人都精神了,手都码疼了上面的图片都是来自于上面的博客,我再贴一次:http://www.tianshouzhi.com/api/tutorials/netty/221