实例解析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 相关文章推荐
Python3基础之输入和输出实例分析
Aug 18 Python
Python实现的彩票机选器实例
Jun 17 Python
实例讲解Python中global语句下全局变量的值的修改
Jun 16 Python
基于Linux系统中python matplotlib画图的中文显示问题的解决方法
Jun 15 Python
Python import与from import使用及区别介绍
Sep 06 Python
Python语言快速上手学习方法
Dec 14 Python
Python去除字符串前后空格的几种方法
Mar 04 Python
Python 使用 attrs 和 cattrs 实现面向对象编程的实践
Jun 12 Python
django项目用higcharts统计最近七天文章点击量
Aug 17 Python
Python extract及contains方法代码实例
Sep 11 Python
分享PyCharm最新激活码(真永久激活方法)不用每月找安装参数或最新激活码了
Dec 27 Python
4种方法python批量修改替换列表中元素
Apr 07 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
php 常用类整理
2009/12/23 PHP
PHP同时连接多个mysql数据库示例代码
2014/03/17 PHP
windows 2008r2+php5.6.28环境搭建详细过程
2019/06/18 PHP
基于jQuery实现的当离开页面时出现提示的实现代码
2011/06/27 Javascript
Javascript简单实现可拖动的div
2013/10/22 Javascript
jQuery中dequeue()方法用法实例
2014/12/29 Javascript
遍历js中对象的属性和值的实例
2016/11/21 Javascript
详解微信小程序开发之——wx.showToast(OBJECT)的使用
2017/01/18 Javascript
jquery pagination分页插件使用详解(后台struts2)
2017/01/22 Javascript
Nodejs之http的表单提交
2017/07/07 NodeJs
EasyUI Tree树组件无限循环的解决方法
2017/09/27 Javascript
关于HTML5的data-*自定义属性的总结
2018/05/05 Javascript
一步一步实现Vue的响应式(对象观测)
2019/09/02 Javascript
[52:26]完美世界DOTA2联赛决赛 FTD vs Phoenix 第一场 11.08
2020/11/11 DOTA
让python的Cookie.py模块支持冒号做key的方法
2010/12/28 Python
python删除文件示例分享
2014/01/28 Python
基于Python实现的百度贴吧网络爬虫实例
2015/04/17 Python
用Python编写简单的定时器的方法
2015/05/02 Python
Python多线程下载文件的方法
2015/07/10 Python
shell命令行,一键创建 python 模板文件脚本方法
2018/03/20 Python
Python实现动态添加属性和方法操作示例
2018/07/25 Python
pymongo中聚合查询的使用方法
2019/03/22 Python
python如何基于redis实现ip代理池
2020/01/17 Python
俄罗斯韩国化妆品网上商店:Cosmasi.ru
2019/10/31 全球购物
期末总结的个人自我评价
2013/11/02 职场文书
中秋节主持词
2014/04/02 职场文书
总经理人事任命书
2014/06/05 职场文书
中学生运动会新闻稿
2014/09/24 职场文书
简单的离婚协议书范本
2014/11/16 职场文书
2014年社区个人工作总结
2014/12/02 职场文书
教师文明餐桌光盘行动倡议书
2015/04/28 职场文书
CAD实训总结范文
2015/08/03 职场文书
公司管理建议书
2015/09/14 职场文书
门面租赁合同范文
2019/08/06 职场文书
嵌入式Redis服务器在Spring Boot测试中的使用教程
2021/07/21 Redis
使用pipenv管理python虚拟环境的全过程
2021/09/25 Python