如何理解:同步异步阻塞非阻塞BIONIOAIO?
Posted 黑马程序员官方
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何理解:同步异步阻塞非阻塞BIONIOAIO?相关的知识,希望对你有一定的参考价值。
有关于同步/异步/阻塞/非阻塞/BIO/NIO/AIO的内容是面试的高频问题了,网上相关内容很多,汇总起来的很少。
常见的误区
假设有一个展示用户详情的需求,分两步,先调用一个HTTP接口拿到详情数据,然后使用合适的视图站视详情数据。
如果网速很慢,代码发起一个HTTP请求后,就卡住不动了,直到十几秒后才拿到HTTP响应,然后继续往下执行。
这个时候你问别人,刚刚代码发起的这个请求是不是一个同步请求,对方一定回答是,这是对的。
但是我们要问为什么是呢?很多人都会说:“因为发起请求之后,代码就卡住不动了,直到拿到响应之后才可以继续往下执行。”【这是不对的,因果关系弄反了!】
因为内核空间里的对应函数会卡住不动,造成用户空间发起的系统调用卡住不动,继而使程序里的用户代码卡住不动了。卡着不动知识同步请求的一个副作用,并步能用它来定义同步请求,那么该如何定义呢?
同步:就是实时处理(打电话)
可以理解为在执行完一个函数或者方法之后,一直等待系统返回值或者消息,这时程序是出于阻塞的,只有接受到返回值或者消息后才能往下执行其他的命令。
也就是服务器一接受到客户请求,马上相应,这样客户端可以在最短时间内得到结果,但是如果多个客户端,或者 一个客户端发出请求很频繁的时候,服务器午发同步处理,就会造成拥塞。
同步像是打电话,通信双方不断(我们是同时进行)你一句我一句这样的好处是:对方想表达的信息我马上就能收到,但是我在打电话,我无法做别的事情。
异步:就是分时处理(如收发短信)
服务器接受到客户端请求后并不是立即处理,而是等待服务器比较空闲的时候加以处理,可以避免涌塞。
异步如同收发短信,打电话是双方都要在线,短信呢,另一方是不用在手机旁的,也不用一直等着手机来没有短信。
对于写程序,同步往往会阻塞,没有数据过来,就一直等着,异步就步会阻塞。没有数据我就干别的事情,有数据的时候我再处理数据。
下面我们再来看看图解:
阻塞非阻塞
阻塞与非阻塞是描述线程再访问某一个资源的时候,数据是否准备就绪的一种处理方式,当数据没有准备就绪的时候:
- 阻塞:线程持续等待资源中数据准备完成,直到返回响应结果。
- 非阻塞:线程池直接返回结果,不会持续等待资源准备数据结束后才响应结果。
我们可以把阻塞理解成堵车,一动不动;非阻塞就是路通了。
计算机当中,一般阻塞的时候只能等着,因为这是最容易实现的,只需要挂起线程,让出CPU即可,再满足条件的时候会重新调度该线程。
- 所谓同步/异步,关注的是能不能同时开工。
- 所谓阻塞/非阻塞,关注的是能不能动。
通过推理进行组合:
同步阻塞,不能同时开工,也不能动。只有一条小道,一次只能过一辆车,可悲的是还TMD的堵上了。
同步非阻塞,不能同时开工,但可以动。只有一条小道,一次只能过一辆车,幸运的是可以正常通行。
异步阻塞,可以同时开工,但不可以动。有多条路,每条路都可以跑车,可气的是全都TMD的堵上了。
异步非阻塞,可以工时开工,也可以动。有多条路,每条路都可以跑车,很爽的是全都可以正常通行。
是不是很容易理解啊。其实它们的关注点是不同的,只要搞明白了这点,组合起来也不是事儿。
回到程序里,把它们和线程关联起来:
- 同步阻塞,相当于一个线程在等待。
- 同步非阻塞,相当于一个线程在正常运行。
- 异步阻塞,相当于多个线程都在等待。
- 异步非阻塞,相当于多个线程都在正常运行。
I/O
指的就是读入/写出数据的过程,和等待读入/写出数据的过程。一旦拿到数据后就编程数据操作了,步是IO了。
拿网络IO来说等待的过程就是数据从网络到网卡再到内核的空间,读写的过程就是内核空间和用户空间的互相拷贝。
所谓的IO就包括两个过程,一个是等待数据的过程,一个是读写(拷贝)数据的过程。而且还要明白,一定不能包括操作数据的过程。
阻塞IO和非阻塞IO
应用程序都是运行再用户空间的,所以它们能操作的数据也都在用户空间。按照这样来理解,只要数据没有达到用户空间,用户线程就操作不了。
如果此时用户线程已经参与,那它一定会呗阻塞在IO上,这就是常说的阻塞IO。用户线程呗阻塞在等待数据上或者拷贝数据上。整个流程都是采用一个线性的处理方式:请求数据—>等待数据准备就绪—>等待数据拷贝—>数据拷贝完成,返回结果,但是!如果数据准备过程非常长的话,整个进程的阻塞时间也会非常长,严重影响应用处理效率。
处理流程:
如果此时用户线程已经参与,那它一定会被阻塞在IO上。这就是常说的阻塞IO。用户线程被阻塞在等待数据上或拷贝数据上。
非阻塞IO就是用户线程不参与以上两个过程,即数据已经拷贝到用户空间后,才去通知用户线程,一上来就可以直接操作数据了。
用户线程没有因为IO的事情出现阻塞,这就是常说的非阻塞IO。
处理流程:
同步IO和同步阻塞IO
按照上文中对同步的理解,同步IO是指发起IO请求后,必须拿到IO的数据才可以继续执行。
按照程序的表现形式又分为两种:
- 在等待数据的过程中,和拷贝数据的过程中,线程都在阻塞,这就是同步阻塞IO。
- 在等待数据的过程中,线程采用死循环式轮询,在拷贝数据的过程中,线程在阻塞,这其实还是同步阻塞IO。
网上很多文章把第二种归为同步非阻塞IO,这肯定是错误的,它一定是阻塞IO,因为拷贝数据的过程,线程是阻塞的。
严格来讲,在IO的概念上,同步和非阻塞是不可能搭配的,因为它们是一对相悖的概念。
同步IO意味着必须拿到IO的数据,才可以继续执行。因为后续操作依赖IO数据,所以它必须是阻塞的。
非阻塞IO意味着发起IO请求后,可以继续往下执行。说明后续执行不依赖于IO数据,所以它肯定不是同步的。
因此,在IO上,同步和非阻塞是互斥的,所以不存在同步非阻塞IO。但同步非阻塞是存在的,那不叫IO,叫操作数据了。
所以,同步IO一定是阻塞IO,同步IO也就是同步阻塞IO。
异步IO和异步阻塞/非阻塞IO
按照上文中对异步的理解,异步IO是指发起IO请求后,不用拿到IO的数据就可以继续执行。
用户线程的继续执行,和操作系统准备IO数据的过程是同时进行的,因此才叫做异步IO。
按照IO数据的两个过程,又可以分为两种:
- 在等待数据的过程中,用户线程继续执行,在拷贝数据的过程中,线程在阻塞,这就是异步阻塞IO。
- 在等待数据的过程中,和拷贝数据的过程中,用户线程都在继续执行,这就是异步非阻塞IO。
第一种情况是,用户线程没有参与数据等待的过程,所以它是异步的。但用户线程参与了数据拷贝的过程,所以它又是阻塞的。合起来就是异步阻塞IO。
第二种情况是,用户线程既没有参与等待过程也没有参与拷贝过程,所以它是异步的。当它接到通知时,数据已经准备好了,它没有因为IO数据而阻塞过,所以它又是非阻塞的。合起来就是异步非阻塞IO。
以上是关于如何理解:同步异步阻塞非阻塞BIONIOAIO?的主要内容,如果未能解决你的问题,请参考以下文章