实例解析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读写Excel文件方法介绍
Nov 22 Python
Python的另外几种语言实现
Jan 29 Python
基于Python实现对PDF文件的OCR识别
Aug 05 Python
Python中标准库OS的常用方法总结大全
Jul 19 Python
Python环境搭建之OpenCV的步骤方法
Oct 20 Python
flask + pymysql操作Mysql数据库的实例
Nov 13 Python
Python学习小技巧总结
Jun 10 Python
pandas 按照特定顺序输出的实现代码
Jul 10 Python
Python中的引用和拷贝实例解析
Nov 14 Python
在Tensorflow中查看权重的实现
Jan 24 Python
python:批量统计xml中各类目标的数量案例
Mar 10 Python
python opencv通过4坐标剪裁图片
Jun 05 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桌面中心(一) 创建数据库
2007/03/11 PHP
ThinkPHP实现带验证码的文件上传功能实例
2014/11/01 PHP
php计算指定目录下文件占用空间的方法
2015/03/13 PHP
PHP观察者模式示例【Laravel框架中有用到】
2018/06/15 PHP
PHP实现正则匹配所有括号中的内容
2018/06/22 PHP
PHP vsprintf()函数格式化字符串操作原理解析
2020/07/14 PHP
再次更新!MSClass (Class Of Marquee Scroll通用不间断滚动JS封装类 Ver 1.6)
2007/02/05 Javascript
jquery插件jbox使用iframe关闭问题
2009/02/09 Javascript
基于jQuery的树控件实现代码(asp.net+json)
2010/07/11 Javascript
JavaScript instanceof 的使用方法示例介绍
2013/10/23 Javascript
js通过八个点 拖动改变div大小的实现方法
2014/03/05 Javascript
js实现遮罩层弹出框的方法
2015/01/15 Javascript
IE6-IE9使用JSON、table.innerHTML所引发的问题
2015/12/22 Javascript
jQuery操作Table技巧大汇总
2016/01/23 Javascript
通过js修改input、select默认字体颜色
2017/04/19 Javascript
详解如何在 vue 项目里正确地引用 jquery 和 jquery-ui的插件
2017/06/01 jQuery
jQuery实现获取及设置CSS样式操作详解
2018/09/05 jQuery
微信小程序scroll-view的滚动条设置实现
2020/03/02 Javascript
详解python3中socket套接字的编码问题解决
2017/07/01 Python
DataFrame 将某列数据转为数组的方法
2018/04/13 Python
Python minidom模块用法示例【DOM写入和解析XML】
2019/03/25 Python
Python3.5面向对象与继承图文实例详解
2019/04/24 Python
python selenium循环登陆网站的实现
2019/11/04 Python
纯css3实现走马灯效果
2014/12/26 HTML / CSS
浅谈cookie和localStorage那些事
2019/08/27 HTML / CSS
安全大检查反思材料
2014/01/31 职场文书
大学生社会实践方案
2014/05/11 职场文书
学校节能宣传周活动总结
2014/07/09 职场文书
小学生教师节演讲稿
2014/09/03 职场文书
村党的群众路线教育实践活动工作总结
2014/10/25 职场文书
作文评语怎么写
2014/12/25 职场文书
大三学生英语考试作弊检讨书
2015/01/01 职场文书
2015年班组建设工作总结
2015/05/13 职场文书
基石观后感
2015/06/12 职场文书
退休教师欢送会致辞
2015/07/31 职场文书
VS2019连接MySQL数据库的过程及常见问题总结
2021/11/27 MySQL