New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

同步,异步,阻塞,非阻塞等关系轻松理解 #40

Open
calidion opened this Issue Jul 8, 2016 · 12 comments

Comments

Projects
None yet
9 participants
@calidion
Owner

calidion commented Jul 8, 2016

在IT领域对于同步、异步、阻塞、非阻塞是很多人理解不好的几个概念。
本文试图从最简单的角度去解读他们之间的关系,下面开门见山说明他们的关系。

本质上并没有关系

  1. 同步与异步是关于指令执行顺序的。
  2. 阻塞非阻塞是关于线程与进程的。
  3. 两者本身并没有必然的关联系。

他们产生关系的领域CPU中断与IO

没有IO操作,所有的代码基本都是同步的
有了IO操作后,如果没有多进程多线程,所有代码还是同步的
有了IO操作,有了多进程多线程,代码才有了异步的可能性,同时也产生了阻塞与非阻塞

同步与异步

同步是指代码调用IO操作时,必须等待IO操作完成才返回的调用方式。
异步是指代码调用IO操作时,不必等IO操作完成就返回的调用方式。

同步是最原始的调用方式。
异步则需要多线程,多CPU或者非阻塞IO的支持。

阻塞与非阻塞

阻塞是指调用线程或者进程被操作系统挂起。
非阻塞是指调用线程或者进程不会被操作系统挂起。

异步,同步与 IO,线程,进程,阻塞,非阻塞等的关系

单线程

只有同步,等待IO(Programmed I/O)。
IO都是阻塞的。

多线程(多进程)让非阻塞成为可能

  1. 默认同步,IO调用仍可以是阻塞的。
  2. 异步在多线程中成为可能。IO也可以多路复用,从而对IO进行异步调用可以不产生阻塞。
    而最常用的异步调用是源于异步IO。

阻塞与非阻塞

  1. 同步IO必定是阻塞IO。
    因为同步要求IO处理是线性的,所以当IO调用时必定会阻塞进程或者线程。
  2. 异步IO也一定就是非阻塞IO。

异步在代码上的处理

对于异步,在不同的语言在实现上的处理是不同的。

最基本的形式回调函数

对异步影响最原始的处理方式是回调函数,这种方式基本上可以认为是汇编语言就开始采用的方式。
因为汇编语言对中断的影响本身就是一种回调函数,而中断本身就是一种IO操作。
后来的很多编译语言都是基于回调函数形式的。包括C,C++等

其它对回调的改进 (yield => promise => async/await)

异步调用出现后,会导致代码的执行不再那么直观。
不同的语言针对异步调用引入不少代码同步化的机制。

最常用的机制就是promise , yield, async/await,事件通知

ruby是较早引入yield的语言。
javascript是使用promise被使用的最多语言
async/await源于.net
目前来看最完备的同步化解决方案是async/await 机制

阻塞与非阻塞

  1. 同步代码调用的是同步IO,也就是阻塞IO。(理论上也存在非阻塞IO的可能,但实际上似乎并没有)
  2. 异步代码不一定调用的是异步IO,也可以是同步的IO。所以异步调用不阻塞自己的线程,但是不表示IO线程一定是不阻塞的。因为异步调用的形式并不直接与IO关联,中间还有OS与编程语言参与。所以有异步调用时我们并不能确定调用与IO之间的关系。

同步、异步和IO+代码

  1. 同步异步分IO与代码两种。
  2. 在IO上同步IO等于阻塞IO,异步IO等于非阻塞IO
  3. 在代码上同步代码等同于调用同步IO,等同于调用阻塞IO;但并不表示异步代码一定有异步IO调用,从而也无法确定是不是一定是非阻塞IO。

总结

文章的分析了异步,同步,阻塞,非阻塞,单进程,多进程,同步代码,异步代码的同步化等的概念与关系。
由于他们之间的关系是比较复杂的,未来也存着的技术革新带来的可能性。
希望这篇文章能帮助你更好的去理解他们,并在实际过程中灵活准确的应用。
也欢迎反馈文章中的错误。

@riskers

This comment has been minimized.

riskers commented Oct 25, 2016

node 是单线程非阻塞的,这里说到单线程是同步阻塞的,怎么解释呢?

@calidion

This comment has been minimized.

Owner

calidion commented Oct 25, 2016

因为node有辅助线程,对于大多数情况来讲,js的运行线程只有一个。不过未来也许会有所变化。

@htoooth

This comment has been minimized.

htoooth commented Mar 16, 2017

感觉不对, JAVA NIO 也是多线程吗?

@calidion

This comment has been minimized.

Owner

calidion commented Mar 16, 2017

nio应该是同步代码的异步/非阻塞IO,所以通常没有必要多线程。

@ckey

This comment has been minimized.

ckey commented Mar 23, 2017

同步IO都会有一个阻塞的过程,但是不应该等同于“阻塞IO”,因为“阻塞IO”、“非阻塞IO”和“IO复用”、“消息驱动IO”、“异步IO”同属于是linux下五种IO模式,其中前四种都属于 同步IO,都会有一个阻塞的过程。这个在Richard Stevens的“UNIX® Network Programming Volume 1, Third Edition: The Sockets Networking ”,6.2节“I/O Models ”,中有定义。我想要表达的就是,“阻塞IO”、“非阻塞IO”是专有的名词,如果这时我们再按字面意义来理解使用,就会造成混淆。

@calidion

This comment has been minimized.

Owner

calidion commented Mar 23, 2017

@ckey

其实混淆刚好来源于这本书。书里面将IO没有明确的区分开。

首先IO本身是无所谓阻塞非阻塞,还是同步非同步的。

阻塞非阻塞是针对进程或者线程的调用结果来说的。

而同步或者非同步则是针对代码的调用结果来说。

到于消息驱动IO,则又是基于消息模型来实现的。即可能同步,也可能是异步。

除了IO多路复用是IO本身的属性外,其它的功能都是基于对界的影响来说的。

所以我认为 RS的网络这本书阐述的还是不够明晰的。

@zColdWater

This comment has been minimized.

zColdWater commented Apr 16, 2017

@riskers 是这样的,在Node中,我们JS代码会在同一个线程里面执行,是同步的程式码,但是你会问,比如像我的AJAX异步请求是怎么回事么,原理是这样的, node内置V8内核,你的同步代码会被放在V8内核的堆栈执行,当他执行到异步的方法时,方法其实会立马return,接着执行下面的代码,只是把函数名和参数callback通过V8内核把js方程式的参数传入给C++的方法,其真正执行是在C++程序中的线程池中执行的(其中在linux是libuv,windows是IOCP),再等到任务执行结束通过EventLoop返回给CallBack在V8的callstack里面执行。 这就是Node,一个用单线程语言js如何执行的异步操作。 其实和在浏览器中,是WEBAPIS,原理都是相同的执行异步上,只不过Node分了好多种Phase.

@crisfan

This comment has been minimized.

crisfan commented Jan 27, 2018

"有了IO操作,有了多进程多线程,代码才有了异步的可能性" 这句话应该不对吧,单线程也可以实现异步。

@JerryIreya

This comment has been minimized.

JerryIreya commented Feb 14, 2018

@crisfan 单线程也能异步啊?怎么做到的?

@JadynSky

This comment has been minimized.

JadynSky commented Mar 12, 2018

@crisfan 不对吧,异步的本质就是把任务交给其它的线程做,不做等待。

@courage007

This comment has been minimized.

courage007 commented Jun 6, 2018

IO多路复用(select、epoll)也实现了非阻塞IO。楼主说“异步则需要多线程,多CPU或者非阻塞IO的支持。”,那么是不是可以将IO多路复用理解成异步调用?如果IO多路复用是异步,那么单线程里也存在异步吧。

@calidion

This comment has been minimized.

Owner

calidion commented Jun 6, 2018

@courage007 IO多路复用的前提是多线程/多进程(即将多个IO放在一个独立的线程或者进程处理)。所以不存单线程环境,因此也就无法通过它证明单线程里存在异步了。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment