实例解析Python的Twisted框架中Deferred对象的用法


Posted in Python onMay 25, 2016

Deferred对象结构
Deferred由一系列成对的回调链组成,每一对都包含一个用于处理成功的回调(callbacks)和一个用于处理错误的回调(errbacks)。初始状态下,deffereds将由两个空回调链组成。在向其中添加回调时将总是成对添加。当异步处理中的结果返回时,Deferred将会启动并以添加时的顺序触发回调链。
用实例也许更容易说明,首先来看看addCallback:

from twisted.internet.defer import Deferred
 
def myCallback(result):
  print result
 
d = Deferred()
d.addCallback(myCallback)
d.callback("Triggering callback.")

运行它将会得到如下结果:

Triggering callback.

上例中创建了一个deffered并利用其addCallback方法注册一个用于处理成功的回调。d.callback会启动deffered并调用callback链。传入callback的参数也会被各callback链中的第一个函数接收到。
有addCallback,那另一个错误的分支,我想也能猜测到了那就是addErrorback,同样来看个例子:

from twisted.internet.defer import Deferred
 
def myErrback(failure):
  print failure
 
d = Deferred()
d.addErrback(myErrback)
d.errback(ValueError("Triggering errback."))

运行它将会得到如下结果:

[Failure instance: Traceback (failure with no frames): <type 'exceptions.ValueError'>: Triggering errback.]

可以看出Twisted会把错误封装在Failure里。
值得注意的是,在之前提到过注册回调总是成对的。在使用d.addCallback和d.addErrorback方法时,我们看似只是添加了一个callback或一个errback。而实际上,为了完成这一级回调链的创建,这些方法还会为另一半注册一个pass-through。要记住,回调链总是具有相同的长度。如果要分别指定这一级回调的callback和errback。可以使用d.addCallbacks方法:
d = Deferred()
d.addCallbacks(myCallback, myErrback)
d.callback("Triggering callback.")
那么...今天就先到这里。

进阶示例
接下来就应该来点更为实际的,那就是放进Reactor。先来看一个例子:

from twisted.internet import reactor, defer
 
class HeadlineRetriever(object):
  def processHeadline(self, headline):
    if len(headline) > 50:
      self.d.errback(Exception("The headline ``%s'' is too long!" % (headline,)))
    else:
      self.d.callback(headline)
 
  def _toHTML(self, result):
    return "<h1>%s</h1>" % (result,)
 
  def getHeadline(self, input):
    self.d = defer.Deferred()
    reactor.callLater(1, self.processHeadline, input)
    self.d.addCallback(self._toHTML)
    return self.d
 
def printData(result):
  print result
  reactor.stop()
 
def printError(failure):
  print failure
  reactor.stop()
 
h = HeadlineRetriever()
d = h.getHeadline("Breaking News: Twisted Takes us to the Moon!")
d.addCallbacks(printData, printError)
 
reactor.run()

上例接收一个标题并对其进行处理,如果标题超长会返回超长的错误,否则将其转为HTML并返回。

因所给的标题少于50个字符,故执行以上代码会得到如下返回:

<h1>Breaking News: Twisted Takes us to the Moon!</h1>

有一点值得注意的,上面用到了reactor的callLater方法,它可以用来做定时事件从而模拟一个异步的请求。

如果我们将标题变得很长,比如说:

h = HeadlineRetriever()
d = h.getHeadline("1234567890"*6)
d.addCallbacks(printData, printError)

那结果是可以遇见的:

[Failure instance: Traceback (failure with no frames): <type 'exceptions.Exception'>: The headline ``123456789012345678901234567890123456789012345678901234567890'' is too long!]

我们用图看一下触发流程:
实例解析Python的Twisted框架中Deferred对象的用法

Deferreds中的关键之处
1. Deferreds将会在调用其callback或errback时被触发;
2. Deferreds仅能被触发一次!如果尝试多次触发将会导致AlreadyCalledError异常;
3. 第N级callback或errback中的Exceptions将会传入第N+1级的errback中;如果没有errback,则会抛出Unhandled Error。如果第N级callback或errback中没有抛出Exception或返回Failure对象,那接下来将会由第N+1级中的callback进行处理;
4. callback中返回的结果将会传入下一级callback,并作为其第一个参数;
5. 如果传入errback的错误不是一个Failure对象,那将会被自动包装一次。

Python 相关文章推荐
python中的多线程实例教程
Aug 27 Python
Python中给List添加元素的4种方法分享
Nov 28 Python
举例讲解Python中is和id的用法
Apr 03 Python
Python多线程编程(六):可重入锁RLock
Apr 05 Python
在Django框架中运行Python应用全攻略
Jul 17 Python
python 异常处理总结
Oct 18 Python
Python中工作日类库Busines Holiday的介绍与使用
Jul 06 Python
浅谈Scrapy框架普通反爬虫机制的应对策略
Dec 28 Python
Python 安装第三方库 pip install 安装慢安装不上的解决办法
Jun 18 Python
django 多对多表的创建和插入代码实现
Sep 09 Python
python3实现弹弹球小游戏
Nov 25 Python
python关闭占用端口方式
Dec 17 Python
详解Python的Twisted框架中reactor事件管理器的用法
May 25 #Python
使用Python的Twisted框架编写非阻塞程序的代码示例
May 25 #Python
Python的Twisted框架中使用Deferred对象来管理回调函数
May 25 #Python
使用Python的Twisted框架构建非阻塞下载程序的实例教程
May 25 #Python
Python的Twisted框架上手前所必须了解的异步编程思想
May 25 #Python
Python的re模块正则表达式操作
May 25 #Python
Python的for和break循环结构中使用else语句的技巧
May 24 #Python
You might like
轻松修复Discuz!数据库
2008/05/03 PHP
php中一个有意思的日期逻辑处理
2012/03/25 PHP
浅谈web上存漏洞及原理分析、防范方法(安全文件上存方法)
2013/06/29 PHP
Win2003+apache+PHP+SqlServer2008 配置生产环境
2014/07/29 PHP
thinkPHP框架自动填充原理与用法分析
2018/04/03 PHP
前端开发必须知道的JS之原型和继承
2010/07/06 Javascript
javascript实现日历控件(年月日关闭按钮)
2012/12/12 Javascript
javascript函数声明和函数表达式区别分析
2014/12/02 Javascript
js实现随屏幕滚动的带缓冲效果的右下角广告代码
2015/09/04 Javascript
JS中多步骤多分步的StepJump组件实例详解
2016/04/01 Javascript
Node.js返回JSONP详解
2016/05/18 Javascript
微信小程序如何获知用户运行小程序的场景教程
2017/05/17 Javascript
bootstrap Table服务端处理分页(后台是.net)
2017/10/19 Javascript
vue中$set的使用(结合在实际应用中遇到的坑)
2018/07/10 Javascript
浅谈vue后台管理系统权限控制思考与实践
2018/12/19 Javascript
uni-app实现点赞评论功能
2019/11/25 Javascript
JavaScript十大取整方法实例教程
2020/12/03 Javascript
详解js创建对象的几种方式和对象方法
2021/03/01 Javascript
[01:20]DOTA2 2017国际邀请赛冠军之路无止竞
2017/06/19 DOTA
Python语言技巧之三元运算符使用介绍
2013/03/04 Python
简化Python的Django框架代码的一些示例
2015/04/20 Python
创建pycharm的自定义python模板方法
2018/05/23 Python
Django中的ajax请求
2018/10/19 Python
解析Python的缩进规则的使用
2019/01/16 Python
详解Python的三种拷贝方式
2020/02/11 Python
Pytorch高阶OP操作where,gather原理
2020/04/30 Python
Python使用Matlab命令过程解析
2020/06/04 Python
机械工程系毕业生求职信
2013/09/27 职场文书
物理专业大学生职业生涯规划书
2014/02/07 职场文书
铁路安全事故反思
2014/04/26 职场文书
社区戒毒工作方案
2014/06/04 职场文书
中学推普周活动总结
2015/05/07 职场文书
小学运动会宣传稿
2015/07/23 职场文书
消防宣传标语大全
2015/08/03 职场文书
反腐倡廉心得体会2016
2016/01/13 职场文书
Python天气语音播报小助手
2021/09/25 Python