实例解析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进行新浪微博的mid和url互相转换实例(10进制和62进制互算)
Apr 25 Python
Python3基础之list列表实例解析
Aug 13 Python
用PyInstaller把Python代码打包成单个独立的exe可执行文件
May 26 Python
python写日志文件操作类与应用示例
Jul 01 Python
python实现视频读取和转化图片
Dec 10 Python
如何基于Python实现自动扫雷
Jan 06 Python
PyCharm无法引用自身项目解决方式
Feb 12 Python
python shell命令行中import多层目录下的模块操作
Mar 09 Python
解决pycharm不能自动补全第三方库的函数和属性问题
Mar 12 Python
python:解析requests返回的response(json格式)说明
Apr 30 Python
什么是python的函数体
Jun 19 Python
python将YUV420P文件转PNG图片格式的两种方法
Jan 22 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
Get或Post提交值的非法数据处理
2006/10/09 PHP
PHP中设置时区方法小结
2012/06/03 PHP
PHP迭代器实现斐波纳契数列的函数
2013/11/12 PHP
js函数使用技巧之 setTimeout(function(){},0)
2009/02/09 Javascript
PNG背景在不同浏览器下的应用
2009/06/22 Javascript
JavaScript 应用技巧集合[推荐]
2009/08/30 Javascript
情人节专属 纯js脚本1k大小的3D玫瑰效果
2012/02/11 Javascript
JQUERY 实现窗口滚动搜索框停靠效果(类似滚动停靠)
2013/03/27 Javascript
javascript打印输出json实例
2013/11/11 Javascript
Jquery仿IGoogle实现可拖动窗口示例代码
2014/08/22 Javascript
JavaScript中的this使用详解
2016/07/27 Javascript
浅谈jQuery添加的HTML,JS失效的问题
2016/10/05 Javascript
最常用的jQuery表单验证(简单)
2017/05/23 jQuery
vue 父组件调用子组件方法及事件
2018/03/29 Javascript
vue学习笔记之Vue中css动画原理简单示例
2020/02/29 Javascript
[01:00] DOTA2英雄背景故事第五期之重力引力法则谜团
2020/07/16 DOTA
python实时分析日志的一个小脚本分享
2017/05/07 Python
浅谈Python实现Apriori算法介绍
2017/12/20 Python
使用Python通过win32 COM实现Word文档的写入与保存方法
2018/05/08 Python
Laravel+Dingo/Api 自定义响应的实现
2019/02/17 Python
python变量命名的7条建议
2019/07/04 Python
python 3.6.7实现端口扫描器
2019/09/04 Python
使用turtle绘制五角星、分形树
2019/10/06 Python
Python unittest 自动识别并执行测试用例方式
2020/03/09 Python
Python Scrapy多页数据爬取实现过程解析
2020/06/12 Python
Django路由层URLconf作用及原理解析
2020/09/24 Python
ASOS亚洲:ASOS Asia
2018/03/04 全球购物
西班牙最大的婴儿用品网上商店:Bebitus
2019/05/30 全球购物
贝尔帐篷精品店:Bell Tent Boutique
2019/06/12 全球购物
乐高西班牙官方商店:LEGO Shop ES
2019/12/01 全球购物
琳达·法罗眼镜英国官网:Linda Farrow英国
2021/01/19 全球购物
环保标语大全
2014/06/12 职场文书
乡党委干部党的群众路线教育实践活动个人对照检查材料思想汇报
2014/10/01 职场文书
中学感恩教育活动总结
2015/05/05 职场文书
基于Redis过期事件实现订单超时取消
2021/05/08 Redis
Golang Elasticsearches 批量修改查询及发送MQ
2022/04/19 Golang