同步/异步/阻塞/非阻塞/I/O

同步/异步/阻塞/非阻塞/I/O

一、同步/异步
首先要是多个事物,只有一个事物,是不存在同步或异步的。
同步: 指协同步调。即,多个事物不能同时进行,必须一个一个的来,上一个事物结束后,下一个事物才开始。

那当一个事物正在进行时,其他事物在干嘛呢?

严格来讲并没有要求,但一般都处于“等待”状态,因为后面事物的正常进行都需要依赖前面事物的结果或者前面事物正在使用的资源。

因此,可以认为,同步更希望关注的是从宏观整体来看,多个事物是一种逐个逐个串行化关系,绝对不会出现交叉的情况。

所以,自然不太会关注某个瞬间某个具体事物是处于一个什么状态(即在干什么)。

“排队”场景可以很好的诠释这个理论。凡是在资源少需求多的场景下都会应用到排队。

栗子:排队买火车票事件
售票大厅更注重的是旅客一个一个的到窗口买票,因为一次只能卖一张票,即使大家一窝蜂的围上去,还是一次只能卖一张票,何必呢?挤在一起又不安全。但是有些人非要硬挤,售票大厅就采用排队方式来达到自己的目的。
至于在排队的状态,是看手机还是说话,根本不关心。

除了这种由于资源导致的同步外,还存在一种由于逻辑上的先后顺序导致的同步。
比如,先更新代码,然后编译,接着打包。这些操作由于后一个操作需要使用前一个操作的结果,所以只能按照顺序一个一个的执行。

同步的另2个小点:

  1. 范围,并不需要在全局范围内都去同步,只需要在某些关键的点执行同步即可。栗子:食堂只有一个卖饭窗口,肯定是同步的,一个人买完,另外一个人再买,但是吃饭就不需要等待前一个人先吃完,后一个人才开始吃。这个范围上不是同步的。
  2. 粒度,并不是只有大粒度的事物才有同步,小粒度的事物也有。只不过小粒度的事物同步通常是天然支持的,而大粒度的事物往往需要手工控制。栗子:比如2个线程的同步就需要手工处理,但一个线程的2个语句就是天然同步的。

异步: 步调各异。多个事物可以你进行你的,我进行我的,谁都不用管谁,所有事物都在同步进行中。

总而言之,同步就是多个事物不能同时开工,异步就是多个事物可以同时开工。

注:体会"多个事物":多个线程是多个事物,多个方法多个事物,多个语句是多个事物,多个CPU指令是多个事物。等等等

二、阻塞/非阻塞
阻塞: 阻碍堵塞,遇到阻碍而造成的不能进行
非阻塞: 没有遇到阻塞而继续执行
“堵车” 可以很好的诠释这个理论。
汽车可以正常通行时,就是非阻塞的。一旦堵上了,全部趴窝,一动不动。
因此阻塞关注的是不能动的,非阻塞关注的是可以动的。
不能动的结果就是只能等待,可以动的结果就是继续前行。
对应的程序里阻塞意味着停下来等待,非阻塞表明可以继续向下执行。
阻塞和等待:

等待只是阻塞的一个副作用而已,表明随着时间的流逝,没有任何有意义的事物发生或者进行。

阻塞的真正含义是你关心的事物由于某些原因无法继续进行,因此让你等待。但是你可以做一些其他无关的事物,因为这并不影响你对关系事物的等待。
栗子:在堵车时,你可以干等。也可以玩手机,聊天或者打游戏,吃饭。这些都不影响你对堵车的等待。不过你的车必须待在原地。
在计算机里,是没有人这么灵活的,一般阻塞时,选择干等,因为这个最容易实现,只要挂起线程,让出CPU即可。在条件满足时,会重新调度该线程。
两两组合:
同步/异步:关注的是能不能同时开工
阻塞/非阻塞:关注的是能不能动
同步阻塞:不能同时开工,也不能动。只有一条小道,一次只能过一辆车,可悲的是还堵上了。
同步非阻塞:不能同时开工,但可以动。只有一条小道,一次只能过一辆车,幸运的是可以正常通行。
异步阻塞:可以同时开工,但不可以动。有多条路,每条路都可以跑车,可悲的是,所有的路都路上了。
异步非阻塞:可以同时开工,也可以动。有多条路,每条路都可以跑车,但幸运的是,都可以正常通行。

对应程序里:
同步阻塞,相当于一个线程在等待。
同步非阻塞,相当于一个线程在正常运行。
异步阻塞,相当于多个线程都在等待。
异步非阻塞,相当于多个线程都在正常运行

三、I/O
IO指的是读入/写出数据的过程,和等待读入/写出数据的过程。一旦拿到数据后就变成数据操作了,就不是IO了。
拿网络IO来说,等待的过程就是数据从网络到网卡再到内核空间。读写过程就是内核空间和用户空间的相互拷贝。

所以IO包括2个过程,一个是等待数据的过程,一个是读写(拷贝)数据的过程。而且还要明白,一定不能包括操作数据的过程。

阻塞IO和非阻塞IO
应用程序都是运行在用户空间的,所以它们能操作的数据都在用户空间,所以只要数据没有到达用户空间,用户线程就操作不了。
如果此时用户线程已经参与,那它一定会被阻塞在IO上,这就是常说的阻塞IO,用户线程被阻塞在等待数据上或者拷贝数据上。
非阻塞IO就是用户线程不参与以上2个过程,即数据已经拷贝到用户空间后,才去通知用户线程,一上来就可以直接操作数据了。
用户线程没有因为IO的事情出现阻塞,这就是常说的非阻塞IO。

同步IO和同步阻塞IO
按照上文中对同步的理解,同步IO是指发起IO请求后,必须拿到IO的数据才可以继续执行。
按照程序的表现形式又分为2种:

  1. 在等待数据的过程中,在拷贝数据的过程中,线程都在阻塞,这就是同步阻塞IO。
  2. 在等待数据的过程中,线程采用死循环式轮询,在拷贝数据的过程中,线程在阻塞,还是同步阻塞IO。有些人认为这是同步非阻塞IO,其实不对。
    严格来讲,在IO的概念上,同步和非阻塞是不可能搭配的,因为是一对相悖的概念。
    同步IO意味着必须拿到IO的数据,才可以继续执行。因为后续操作依赖IO数据,所以它必须是阻塞的。
    非阻塞IO意味着发起IO请求后,可以继续往下执行,说明后续执行不依赖于IO数据,所以它肯定不是同步的。
    因此,在IO上,同步和非阻塞是互斥的,所以不存在同步非阻塞IO。但同步非阻塞是存在的,那不叫IO,叫操作数据了。
    所以,同步IO一定是阻塞IO,同步IO也就是同步阻塞IO。

异步IO和异步阻塞/非阻塞IO
按照上面对异步的理解,异步IO指发起IO请求后,不用拿到IO的数据就可以继续执行。
用户线程的继续执行,和操作系统准备IO数据的过程是同时进行的,所以才叫异步IO。

按照IO数据的两个过程,又可以分为两种:

  1. 在等待数据的过程中,用户线程继续执行,在拷贝数据的过程中,线程在阻塞,这就是异步阻塞IO。这种情况用户线程没有参与数据等待的过程,所以是异步的。但用户线程参与了数据拷贝过程,所以它又是阻塞的。合起来就是异步阻塞IO。
  2. 在等待数据的过程中,和拷贝数据的过程中,用户线程都在继续执行,这就是异步非阻塞IO。这种情况是,用户线程既没有参与等待过程与拷贝过程,所以是异步的,当它接到通知时,数据已经准备好了,它没有因为IO数据而阻塞过,所以是非阻塞的,合起来就是异步非阻塞IO。

猜你喜欢

转载自blog.csdn.net/baidu_35160588/article/details/89956192