异步、回调、事件驱动、协程概念辨析

同步和异步
面试问题什么是异步非阻塞
A. 同步
所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。
B. 异步
异步的概念和同步相对。
当一个异步过程调用发出后,先返回,调用者不会立刻得到结果。
实际处理这个调用的部件是在调用发出后,
通过状态、通知来通知调用者,或通过回调函数处理这个调用。
以 Socket为例,
当一个客户端通过调用 Connect函数发出一个连接请求后,调用者线程不用等待结果,可立刻继续向下运行。
当连接真正建立起来以后,socket底层会发送一个消息通知该对象。

在这个语义环境下,阻塞与非阻塞,是指请求的受理者在处理某个请求的状态,如果在处理这个请求的时候不能做其它事情(请求处理时间不确定),那么称之为阻塞,否则为非阻塞。

回调
1、回调是什么:
知乎:回调函数(callback)是什么?
但是有些库函数(library function)却要求应用先传给它一个函数,好在合适的时候调用,以完成目标任务。这个被传入的、后又被调用的函数就称为回调函数(callback function)。
一个对象a将自身传递给另一个对象b,b在某个时间调用a的方法,就叫回调。

2、回调的分类:
文末所说的阻塞式回调就是同步回调,非阻塞式回调就是异步回调。
这里要注意:
事件驱动机制的回调是异步的,回调也可以是同步的,比如jdk实现的观察者模式。

3、从网上截取的一些关于回调的说法,可以帮助理解:
我们常说的同步回调,指的就是一个代码执行过程中,需要等到回调函数完全执行完后,才能往 下走。
异步回调指的是一个代码执行到回调函数时,他可以不需要经过回调结束就能往下走。
而异步回调和同步回调最大的不同就是异步回调里新建了一个子线程。异步回调常见于请求服务器数据,当取到数据时,会进行回调。

回调模型会加大我们的编程负担。

事件驱动模型
事件驱动编程是一种编程范式,这里程序的执行流由外部事件来决定。它的特点是包含一个事件循环,当外部事件发生时使用回调机制来触发相应的处理。事件驱动是设计模式中观察者模式的一个实现。
不用回调函数,也可以实现事件驱动。例如:把事件消息发送到队列,另外一个进程取队列处理即可(没有回调函数)。
这种模型可以解耦事件发送者和接收者之间的联系
事件驱动模型大体思路如下:

  1. 有一个事件(消息)队列;
  2. 鼠标按下时,往这个队列中增加一个点击事件(消息);
  3. 有个循环,不断从队列取出事件,根据不同的事件,调用不同的函数,如onClick()、onKeyDown()等;
  4. 事件(消息)一般都各自保存各自的处理函数指针,这样,每个消息都有独立的处理函数;

事件驱动实现的形式可以是两种:1.事件发生时线程调用对应的回调函数。2.在中断向量上注册事件,事件发生时执行中断程序。
事件驱动使用的线程个数:可以是单线程如Twisted,双线程如Netty。双线程的事件驱动模式,可以自然地异步回调来实现,Netty的运行原理是个典型的双线程事件驱动模型,用一个线程处理所有的连接,这个线程通常是一个循环的方法,当处理一个连接遇到阻塞的操作就将任务丢给其它的线程,主线程接着处理下一个连接。

事件驱动的python实现

协程
协程可以使用同步的方式写异步代码,通过库或者语言的调度来实现并发。协程与回调对比,优势一目了然:代码更清晰直观,更加符合思维习惯。
不是很了解,不多做介绍。

Twisted
但因为twisted属于单线程异步回调,所以在回调函数中的阻塞发生时reactor线程也会阻塞。
同步版本返回的是诗歌内容,而异步版本返回的却是一个deferred。
当然,这个函数是不能随意激活这个deferred的,因为它已经返回了。但这个函数已经启动了一系列事件,这些事件最终将会激活这个deferred。
一个deferred已经绑定了一系列的处理事件。当整个socket数据接收完毕后,就开始进行整个事件的处理。

在这里插入图片描述
那张图显示的是异步编程时的时间片使用。在程序上是表现为三个套接字abc,a就绪,b就绪,c就绪,然后reactor run 后abc同时开始执行(这是异步,因为abc均已返回但并未得到最后的返回结果)。a接收完所有数据之后,开始执行注册好的Deferred,这也是异步,因为deferred在之前已经返回。显然,如果abc使用异步,那么处理过程通过回调函数而不是轮询来执行是一个很自然的行为。这就导致了Deferred也会是一个异步过程。

猜你喜欢

转载自blog.csdn.net/kekefen01/article/details/84206607