计算机领域中的同步和异步的概念和我们平时生活中的同步和异步是不一样的,这就让很多人难以理解。
同步就是整个处理过程顺序执行,当各个过程都执行完毕,并返回结果。是一种线性执行的方式,执行的流程不能跨越。一般用于流程性比较强的程序,比如用户登录,需要对用户验证完成后才能登录系统。
异步则是只是发送了调用的指令,调用者无需等待被调用的方法完全执行完毕;而是继续执行下面的流程。是一种并行处理的方式,不必等待一个程序执行完,可以执行其它的任务,比如页面数据加载过程,不需要等所有数据获取后再显示页面。
他们的区别就在于一个需要等待,一个不需要等待,在部分情况下,我们的项目开发中都会优先选择不需要等待的异步交互方式,比如日志记录就可以使用异步方式进行保存。
本质上并没有关系
- 同步与异步是关于指令执行顺序的。
- 阻塞非阻塞是关于线程与进程的。
- 两者本身并没有必然的关联系。
他们产生关系的领域CPU中断与IO
没有IO操作,所有的代码基本都是同步的
有了IO操作后,如果没有多进程多线程,所有代码还是同步的
有了IO操作,有了多进程多线程,代码才有了异步的可能性,同时也产生了阻塞与非阻塞
同步与异步
同步是指代码调用IO操作时,必须等待IO操作完成才返回的调用方式。
异步是指代码调用IO操作时,不必等IO操作完成就返回的调用方式。
同步是最原始的调用方式。
异步则需要多线程,多CPU或者非阻塞IO的支持。
阻塞与非阻塞
阻塞是指调用线程或者进程被操作系统挂起。
非阻塞是指调用线程或者进程不会被操作系统挂起。
异步,同步与 IO,线程,进程,阻塞,非阻塞等的关系
单线程
只有同步,等待IO(Programmed I/O)。
如果有多线程,那么这些IO都是阻塞的。
多线程(多进程)让非阻塞成为可能
- 默认同步,IO调用仍可以是阻塞的。
- 异步在多线程中成为可能。IO也可以多路复用,从而对IO进行异步调用可以不产生阻塞。
而最常用的异步调用是源于异步IO。
阻塞与非阻塞
- 同步IO必定是阻塞IO(如果是多线程的环境的话,单线程无所谓阻塞)。
因为同步要求IO处理是线性的,所以当IO调用时必定会阻塞进程或者线程。 - 异步IO也一定就是非阻塞IO。
异步在代码上的处理
对于异步,在不同的语言在实现上的处理是不同的。
最基本的形式回调函数
对异步影响最原始的处理方式是回调函数,这种方式基本上可以认为是汇编语言就开始采用的方式。
因为汇编语言对中断的影响本身就是一种回调函数,而中断本身就是一种IO操作。
后来的很多编译语言都是基于回调函数形式的。包括C,C++等
其它对回调的改进 (yield => promise => async/await)
异步调用出现后,会导致代码的执行不再那么直观。
不同的语言针对异步调用引入不少代码同步化的机制。
最常用的机制就是promise , yield, async/await,事件通知
ruby是较早引入yield的语言。
javascript是使用promise被使用的最多语言
async/await源于.net
目前来看最完备的同步化解决方案是async/await 机制
阻塞与非阻塞
- 同步代码调用的是同步IO,也就是阻塞IO。(理论上也存在非阻塞IO的可能,但实际上似乎并没有)
- 异步代码不一定调用的是异步IO,也可以是同步的IO。所以异步调用不阻塞自己的线程,但是不表示IO线程一定是不阻塞的。因为异步调用的形式并不直接与IO关联,中间还有OS与编程语言参与。所以有异步调用时我们并不能确定调用与IO之间的关系。
同步、异步和IO+代码
- 同步异步分IO与代码两种。
- 在IO上同步IO等于阻塞IO,异步IO等于非阻塞IO
- 在代码上同步代码等同于调用同步IO,等同于调用阻塞IO;但并不表示异步代码一定有异步IO调用,从而也无法确定是不是一定是非阻塞IO。
总结
文章的分析了异步,同步,阻塞,非阻塞,单进程,多进程,同步代码,异步代码的同步化等的概念与关系。
由于他们之间的关系是比较复杂的,未来也存着的技术革新带来的可能性。
希望这篇文章能帮助你更好的去理解他们,并在实际过程中灵活准确的应用。
也欢迎反馈文章中的错误。