Node.js前置知识点(二):同步/异步
前言
本文是node.js前置知识系列文章的第二篇,主要介绍 同步/异步;阻塞/非阻塞 的相关概念 (参考来源 见文末的 Reference)
一 什么是 同步/异步
同样从 What的角度开始介绍,由浅入深的理解同步/异步。
同步或者不同步,判断依据是 A向B后发出调用请求后,B是否把处理后的结果随请求响应一起返回,它的标志是:
- 有两个相关主体:调用者(A)和被调用者(B);
- 关注的是 被调用者(B)的运行处理结果 是否随着 请求响应返回;
如果在被调用后,B能把处理生成的结果,随着 请求响应一起返回,那么就是同步的;
反之,如果调用请求发出后,调用者A没有立刻得到结果;
而是过一段时间(可能是B处理完成了,也可能是某些事件被触发,满足了B的返回机制了),被调用者B 再通知调用者A(或通过回调函数处理 A对B的调用),这种方式就叫做异步。
摘录知乎的通俗例子,更直观的理解一下:
你打电话问书店老板有没有《分布式系统》这本书,
如果是同步通信机制,书店老板会说,你稍等,”我查一下",然后开始查啊查,等查好了(可能是5秒,也可能是一天)告诉你结果(返回结果);
而异步通信机制,书店老板直接告诉你我查一下啊,查好了打电话给你,然后直接挂电话了(不返回结果)。然后查好了,他会主动打电话给你。在这里老板通过“回电”这种方式来回调。
所以结论1:
同步/非同步 关注的是 被调用者B的结果是否请求响应一起返回;
二 什么是阻塞/非阻塞
接下来再来理解什么是阻塞/非阻塞,
它们的判断依据是 调用者A的程序处理状态,标志是:
- 有两个相关主体:调用者(A)和被调用者(B);
- 关注的是 A在发出调用请求后,自己内部程序 的执行状态;
假设A的伪代码如下:
function A() {
functionB (1);
functionB (2);
}
function B() {
...do something...
}
A()
上面的例子里,运行A()后,首先会按顺序执行 functionB (1) 语句(这里默认是单线程情况,多线程的暂不考虑):
-
如果A一直停在这一句functionB(1),直到等到返回结果,才执行下一句的 functionB (2),那么A就是阻塞的;
-
如果A在执行了functionB(1)后,不等这步语句的返回结果,就立刻执行下一句的 functionB (2),那么 A就是非阻塞的。
同样摘录上文的通俗例子,更直观的理解一下:
你打电话问书店老板有没有《分布式系统》这本书,
如果是阻塞式调用,你会一直把自己“挂起”,直到得到这本书有没有的结果;
如果是非阻塞式调用,你不管老板有没有告诉你,你自己先一边去玩了, 当然你也要偶尔过几分钟check一下老板有没有返回结果。
在这里阻塞与非阻塞与是否同步异步无关。跟老板通过什么方式回答你结果无关。
所以结论2:
阻塞/非阻塞 关注的是调用者A在发出调用请求后,自己内部程序 的执行状态;
三 同步/非同步 & 阻塞/非阻塞的 可能情况
从上文我们知道, 同步/非同步 & 阻塞/非阻塞是不同的两个概念,他们的组合情况可能有:
-
同步阻塞:
A的第1条语句是 请求调用B,B 即时把处理结果,随着请求响应一起返回(这里的即时 可能是很快的几ms,也可能是很久的死循环);
只有拿到这句结果后, A才会继续执行下面的语句; -
同步非阻塞:
A的第1条语句是 请求调用B,B只是返回请求响应,告诉A我正在处理中;(注意!!!这里的返回请求响应只是便于理解,实际并不存在)
A收到响应后,继续执行下面的第2条语句,不等待第一条语句的 返回结果; -
异步阻塞:
A的第1条语句是 请求调用B,B只是返回请求响应,告诉A我正在处理中;(同上!!!这里的返回请求响应只是便于理解,实际并不存在)
A收到响应后,继续等待B的 结果返回通知,
一直等到 返回结果后,才执行下面的第2条语句; -
异步非阻塞:
A的第1条语句是 请求调用B,B只是返回请求响应,告诉A我正在处理中;(同上!!!这里的返回请求响应只是便于理解,实际并不存在)
A收到响应后,就开始执行第2条语句,而不等待第1条语句的处理结果;
直到以后,B通知A 或者 A轮询发现后,才拿到之前语句的处理结果。
四 备注
以上就是对 同步/异步 ,阻塞/非阻塞的 比较简单的理解方式,实际更深入的理解需要以后看 计算机体系结构和操作系统的相关书籍,才能更深入的理解。
万丈高楼平地起,风物长宜放眼量。
五 Refernce:
知乎问题:怎样理解阻塞非阻塞与同步异步的区别