实例解析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服务器拒绝服务攻击代码
Jan 16 Python
python常用web框架简单性能测试结果分享(包含django、flask、bottle、tornado)
Aug 25 Python
Python RuntimeError: thread.__init__() not called解决方法
Apr 28 Python
python自动zip压缩目录的方法
Jun 28 Python
Python 专题二 条件语句和循环语句的基础知识
Mar 19 Python
Python下载网络文本数据到本地内存的四种实现方法示例
Feb 05 Python
Python实现制度转换(货币,温度,长度)
Jul 14 Python
python用match()函数爬数据方法详解
Jul 23 Python
使用pymysql查询数据库,把结果保存为列表并获取指定元素下标实例
May 15 Python
Django 解决distinct无法去除重复数据的问题
May 20 Python
Pandas之缺失数据的实现
Jan 06 Python
Python中的socket网络模块介绍
Jul 23 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
一个高ai的分页函数和一个url函数
2006/10/09 PHP
CSS心形加载的动画源码的实现
2021/03/09 HTML / CSS
可拖动窗口,附带鼠标控制渐变透明,开启关闭功能
2006/06/26 Javascript
获取任意Html元素与body之间的偏移距离 offsetTop、offsetLeft (For:IE5+ FF1 )[
2006/12/22 Javascript
javascript delete 使用示例代码
2010/03/29 Javascript
基于jquery的页面划词搜索JS
2010/09/14 Javascript
多浏览器兼容性比较好的复制到剪贴板的js代码
2011/10/09 Javascript
js 使FORM表单的所有元素不可编辑的示例代码
2013/10/17 Javascript
JS延迟加载加快页面打开速度示例代码
2013/12/30 Javascript
JavaScript 异常处理 详解
2015/02/06 Javascript
JQuery分屏指示器图片轮换效果实例
2015/05/21 Javascript
js实现表单Radio切换效果的方法
2015/08/17 Javascript
JS实现Fisheye效果动感放大菜单代码
2015/10/21 Javascript
vue2 前后端分离项目ajax跨域session问题解决方法
2017/04/27 Javascript
移动端效果之Swiper详解
2017/10/09 Javascript
element el-input directive数字进行控制
2018/10/11 Javascript
微信小程序在ios下Echarts图表不能滑动的问题解决
2019/07/10 Javascript
JavaScript装饰者模式原理与用法实例详解
2020/03/09 Javascript
python从ftp下载数据保存实例
2013/11/20 Python
Python手机号码归属地查询代码
2016/05/04 Python
深入理解Python装饰器
2016/07/27 Python
Python生成随机数组的方法小结
2017/04/15 Python
详解python之配置日志的几种方式
2017/05/22 Python
Python实现的三层BP神经网络算法示例
2018/02/07 Python
css3+伪元素实现鼠标移入时下划线向两边展开的效果
2017/04/25 HTML / CSS
JACK & JONES英国官方网站:欧洲领先的男装生产商
2017/09/27 全球购物
企业管理专业个人求职信范文
2013/09/24 职场文书
通息工程毕业生自荐信
2013/10/16 职场文书
音乐学院硕士生的自我评价分享
2013/11/01 职场文书
音乐器材管理制度
2014/01/31 职场文书
2014年元旦活动方案
2014/02/15 职场文书
群众路线领导对照材料
2014/08/23 职场文书
债务纠纷委托书
2014/08/30 职场文书
四年级学生期末评语
2014/12/26 职场文书
英语导游词
2015/02/13 职场文书
2015年电话客服工作总结
2015/05/18 职场文书