实例解析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中动态获取对象的属性和方法的教程
Apr 09 Python
Python实现在线暴力破解邮箱账号密码功能示例【测试可用】
Sep 06 Python
利用Django内置的认证视图实现用户密码重置功能详解
Nov 24 Python
十分钟搞定pandas(入门教程)
Jun 21 Python
Python命令行参数解析工具 docopt 安装和应用过程详解
Sep 26 Python
pytorch 实现tensor与numpy数组转换
Dec 27 Python
python分别打包出32位和64位应用程序
Feb 18 Python
Python第三方包之DingDingBot钉钉机器人
Apr 09 Python
详解Flask前后端分离项目案例
Jul 24 Python
如何将json数据转换为python数据
Sep 04 Python
微软开源最强Python自动化神器Playwright(不用写一行代码)
Jan 05 Python
matplotlib画混淆矩阵与正确率曲线的实例代码
Jun 01 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简单提示框alert封装函数
2010/08/08 PHP
浅谈php错误提示及查错方法
2015/07/14 PHP
php获得文件夹下所有文件的递归算法的简单实例
2016/11/01 PHP
PHP一致性hash分布式算法封装类定义与用法示例
2018/08/04 PHP
php中的依赖注入实例详解
2019/08/14 PHP
Jquery进度条插件 Progress Bar小问题解决
2011/07/12 Javascript
js动态控制table的tr、td增加及删除的具体实现
2014/04/30 Javascript
setInterval计时器不准的问题解决方法
2014/05/08 Javascript
javascript模拟map输出与去除重复项的方法
2015/02/09 Javascript
jquery简单实现外部链接用新窗口打开的方法
2015/05/30 Javascript
如何写好你的JavaScript【推荐】
2017/03/02 Javascript
神级程序员JavaScript300行代码搞定汉字转拼音
2017/05/20 Javascript
浅谈react-native热更新react-native-pushy集成遇到的问题
2017/09/30 Javascript
微信小程序radio组件使用详解
2018/01/31 Javascript
js+html实现周岁年龄计算器
2019/06/25 Javascript
Vue3.0的优化总结
2020/10/16 Javascript
前端vue如何使用高德地图
2020/11/05 Javascript
Python表示矩阵的方法分析
2017/05/26 Python
回调函数的意义以及python实现实例
2017/06/20 Python
python 调用c语言函数的方法
2017/09/29 Python
pandas中Timestamp类用法详解
2017/12/11 Python
python调用外部程序的实操步骤
2019/03/04 Python
详解python 爬取12306验证码
2019/05/10 Python
python中metaclass原理与用法详解
2019/06/25 Python
解决yum对python依赖版本问题
2019/07/05 Python
基于jupyter代码无法在pycharm中运行的解决方法
2020/04/21 Python
网页布局中CSS样式无效的十个重要原因详解
2017/08/10 HTML / CSS
介绍下static、final、abstract区别
2015/01/30 面试题
大学毕业感言200字
2014/03/09 职场文书
五年级学生评语
2014/04/22 职场文书
数学教研活动总结
2014/07/02 职场文书
乡镇安全生产目标责任书
2014/07/23 职场文书
实习报告怎么写
2019/06/20 职场文书
Golang实现AES对称加密的过程详解
2021/05/20 Golang
php实例化对象的实例方法
2021/11/17 PHP
使用Django框架创建项目
2022/06/10 Python