Chinaunix首页 | 论坛 | 博客
  • 博客访问: 46129
  • 博文数量: 9
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 100
  • 用 户 组: 普通用户
  • 注册时间: 2013-12-12 17:58
个人简介

熬着熬着,让时间熬成想要的那个自己,一个美丽的人。

文章分类

全部博文(9)

文章存档

2016年(1)

2014年(7)

2013年(1)

分类: Python/Ruby

2013-12-17 16:50:57

随着事件驱动程序设计的发展,在一个应用中处理好事件的成功或出错的事例变得愈加困难。如果不能成功的注册一个合适的回调函数,就会导致一个程序在处理事件过程中卡住,这个永远都不会发生。错误信息可能通过应用程序的各层,从堆积的网络传递一系列的回调函数。

 

Twisted提供了一个更为完美的抽象--Deferred--来管理哲学回调函数。这一章节将应用Deferreds进行练习,然后通过几个结合了clientserver的例子来解释Deferreds的工作原理。

 

本书剩下的部分我们都会用Deferreds来编写异步的serverclient

 

Deferreds能做什么,不做什么

 

提前消除一个误解是很有必要的:

l Deferreds 能帮助你编写异步的代码

l Deferreds 不能自动地让代码异步或者非阻塞。把一个同步的函数转变为异步函数,需要被重构返回到Deferreds,回调正式通过Deferreds来注册的。

 

练习能够帮助你挖掘出构建异步代码的直觉。我们先来看一下Deferreds,然后就可以开始进行一些练习。

 

Deferreds 对象的结构

Deferreds有两个回调链,一个是成功的回调(callbacks),另一个是错误信息的回调(errbacks)。 Deferreds 开启两个空的回调链。 你给Deferreds增加callbackserrbacks来处理事件在每个节点的成功或出错。 当一个异步的结果到达,Deferreds就会被引‘爆’,相应的callbacks或者errbacks就会被有序激活,加入到之前开启的回调链里面。图3-1表明了一个Deferreds和它的回调链。


      图3-1 Deferreds以及两条回调链

 

为了能更具体的理解Deferreds是如何工作的,我们先来创建Deferreds,并用其注册callbacserrbacks,然后不涉及reactor来激活它们。

 

Example 3-1创建了一个Deferred,并用它的addCallback 方法在回调链中记录了myCallback方法,回调链里面只包含myCallback。传给callback的参数也作为参数传给了回调链中的第一个方法。

 

Example 3-2创建了一个Deferred,并用它的addErrback方法在errback链中记录了myErrback函数, d.errback 激活了 d并且唤醒了errback链中的第一个函数,这个errback链中只有myErrback函数。传给errback的参数在传给errback方法前被绑定成一个失败的对象。

 

FailureTwisted对异步通信中出现的Exception的一种完善。它包含了异步错误实际发生的堆栈跟踪记录,当然也可能不是当前的堆栈信息。

 

一个异步的事件可能有很多处理的步骤,每一步骤都需要一个层级的callbackserrbacks。比如,一个web请求可能需要反序列化、格式化然后引起数据库插入,其中的每一步都可能出错。Deferreds使得在一个地方管理这些多层级的成功或失败的变得简便。

 

用一个Deferred来记录多层级的callbackserrbacks,只是它们按照你所需要的用addCallbackaddErrback唤醒的顺序的连接到回调链,就如Example 3-3. Deferredcallbackerback返回的结果被作为第一个参数传给了下一个callback或者errback

 

注意到记录的一个callback也记录了‘pass-through’给同级的errback 链,相同的,记录一个errback也会记录一个‘pass-through’给同级的callback链。因此两个链具有相同的长度。

 

Deferreds也炫了一个addCallbacks方法,这个方法同时记录了一个callback也一个errback,在它们的不相干的回调链中的同一层级。比如:

 

回调链以及Reactor中应用Deferreds

 

以上我们以及练习了不用reactor的应用callbackserrbacks,现在我们来看看在Reactor中如何应用。

 

Example 3-4 检索了一个标题,然后处理这个标题。把这个标题转换为HTML并输出,或者输出错误信息检测是否标题过长。

 

由于给出的标题长度不够50HeadlineRetriever引着了回调链,激活了_toHTML然后printHeadline输出了标题。

 

Example 3-4  用了一个比较重要的reactor方法,callLater,可以用这个方法来设定时间的发生时间。在这个例子中,我们在getHeadline用该方法在1s后假装一个异步的时间到达。

 

如果我们用下面的三行代替了reactor.run()中的会发生什么?

修改之后,HeadlineRetriever触发了一个太长的标题从而点燃了errback链,a pass-throught(从这个调用到addCallback),然后是printError. 3-2 标明了通过整个Deferred的进行的路径。

 

 


3-2.

 

练习:下面这些Deferreds回调链是如何处理的?

 

这一部分,我们会查看一系列的例子,从Example 3-5 函数是如何从Deferre里以callbacks或者errbacks并且不同的方式连接到回调链里面的,然后被引爆。每一个例子,思考一下callbackserrbacks是如何一次被执行的,输出的结果又是什么。例子中的输出结果包括回溯、回溯中间是如何被简短清晰的实现的。

 

Exercise 1

Deferred 触发后,执行从高回调链的顶端开始执行,先是callback1,接着是callback2,结果就是:

 

Exercise 2

Deferred 触发后,运行从回调链的顶端开始执行,先是callback1,然后是callback2,最后是callback3Callback3引出了一个异常处理,由于没有已经记录的errback来处理这个异常,程序所以终止,返回给用户一个不能处理的错误。

 

Exercise 4

Deferred 触发了erback链,给errback的第一个参数是一个Failure(如果必须的话,Failure是被包裹覆盖的,比如这个例子里面的就是用‘Test’字符串);errback1 返回来一个Failure,因此这个Failure作为参数又直接被传给了下一个errback来处理。由于没有其余的errback来处理这个Failure,异常以无法处理的错误信息返回并终止。

 

Exercise 5

Deferred 触发了errback链,errback1 传递了一个Failureerrback3errback3处理了这个Failure,它没有引发异常,也不返回Failure,它返回了一个字符串,因为下一个层级再没有callback来处理这个结果,Deferred 完成了触发的整个过程。

 

Exercise 6

Deferred 触发了errback链,从errback2开始,errback2引出一个异常。由于引发异常把参数传给了errback链中的下一个errback,但是没有errback来处理异常,因此导致了未处理错误:

 

addCallbacks的真相

 

到现在针对Deferred你应该已有了练习心得,但有一点还需要强调:addCallbacks 并不是和addCallbackaddErrback一样有序的调用。

 

差别是什么呢?

 

addCallbacks

记录一个包括callbackcallback链和包括errbackerrback链,两串回调链是同一个  层级

addCallback

记录一个包含callbackcallback链,和一个包含pass-througherrback链,仅仅返回        结果给它

addErrback

记录一个包含errbackerrback链和一个包含pass-throughcallback

 

显著的差别就是callbackserrbacks一起记录,addCallbacks却不用于交互的。 换句话说,用addCallbacks同时记录了一个callback和一个errback,而这个errback不能处理callback引发的异常:callback链中的第N层级引发的异常是在errback链中的第N+1层级进行处理的。

 

3-3和图3-4 描述了addCallbacks调用和addCallback/addErrback连续调用的差别。


存在这样的差别,接下来的Deferred链是做什么的呢?

Exercise 7

 

Deferred链和Exercise 3里面的一样,除了有序的调用addCallbackcallback3)和addErrbackerrback3),代替的是addCallbacks。 这些代码块是完全不同的!在Exercise 3里面,callback3和一个pass-through分别作为callbackerrback来第3层级注册的,然后是一个pass-through和一个errback3分别作为callbackerrback在第4层级注册。这就意味着第3层级的异常可以在第4层级处理。

 

Exercise 7 里面,callback3 errback3 分别跟随callbackerrback在第3层级记录。这就意味着没有第4层级的errback来处理上一层级引发的异常。结果就是:

 

 

Exercise 8

Deferred触发了callback链,callback3引发了一个异常,所以被传给errback链的下一个层级errback3errback3处理了异常,然后传回callback链,callback1被唤醒。结果:

 

Deferreds的要点:

这一部分重申了Deferred的重点,并引入了部分新的要点:

 

1. Deferred通过调用callbackerrback方法来触发激活;

2. Deferred 只能被激活一次,如果试图再次触发就会导致AlreadyCalledError这个错误这能预防突发的多次处理一个事件;

3. Callback链中的第N层级的异常是在errback链中第N+1层级的errback来处理。如果这个层级没有errback,程序中断,返回Unhandle Error不能处理的错误。如果一个第N层级的callback或一个errback没有引发异常也没有返回Failure,操控被传递到第N+1层的callback。注意,这意味着errbacks!如果一个errback不能产生错误,操控就被转到callback链了,操控只是根据处理事件的结果来在 errbackcallback链之间穿插进行;

4. Deferred链中的callback返回的结果作为第一个参数传给了链中下一个callback。这就是允许回调链处理结果的依据。不要忘记返回结果给callbacks以进行下一步的处理!

5. 如果传给errback的对象已经不是一个Failure,就被捆绑到一个。包括触发Deferred的传给errback链的对象和callbacks引发的异常,这也会把操控转到errback链进行处理。

 

API Deferred的总结

Deferred API 还有一个方法来增加callback--addBothaddBoth是记录同样的callbackcallback链和errback链。注意,当我们还没给callback传参数的时候,API才允许这么做。

支持的方法有:

addCallback

增加一个callbackcallback链,增加一个pass-througherrback

addErrback

    增加一个errbackerrback链,增加一个pass-throughcallback链。

addCallbacks

增加一个callbackerrback分别给callback链和errback

addBoth

增加同样的callbackcallback链和errback链,类似于try/except/finally中的finally部分的同步逻辑

 

其他练习和进度

这一章介绍了DeferredDeferred是一种抽象,简洁集中的管理异步程序中的成功的callbacks或者异常。我们会在编写HTTP 服务器和客户端的接下来两章中用到DeferredTwisted Core HOWTO 有两个主要的文档介绍Deferreds, 一个是整体应用,另一个是知道生成Deferred的编写函数。

 

 


阅读(969) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:第5章 web client

给主人留下些什么吧!~~