第十部分:增强defer功能的客户端

作者:[email protected]http://krondo.com/?p=1956  译者:杨晓伟(采用意译)

可以从这里从头开始阅读这个系列。

版本5.0

现在我们将要向诗歌下载客户端添加一些新的处理逻辑,包括在第九部分提到要添加的功能。不过,首先我要说明一点:我并不知道如何实现Byronification引擎。那超出了我的编程能力范围。取而代之的,我想实现一个简单的功能,即Cummingsifier。其只是将诗歌内容转换成小写字母:

def cummingsify(poem)
    return poem.lower()

这个方法如此之简单以至于它永远不会出错。版本5.0的实现代码在twisted-client-5/get-poetry.py文件中。我们使用了修改后的 cummingsify,其会随机地选择以下行为:

1.返回诗歌的小写版本

2.抛出一个GibberishError异常

3.抛出一个ValueError

这样,我们便模拟出来一个会因为各种意料不到的问题而执行失败的复杂算法。其它部分的仅有的改变在方法poetry_main中:

def poetry_main():
    addresses = parse_args()
    from twisted.internet import reactor
    poems = []
    errors = []
    def try_to_cummingsify(poem):
        try:
            return cummingsify(poem)
        except GibberishError:
            raise
        except:
            print ‘Cummingsify failed!‘
            return poem

    def got_poem(poem):
        print poem
        poems.append(poem)

    def poem_failed(err):
        print >>sys.stderr, ‘The poem download failed.‘
        errors.append(err)

    def poem_done(_):
        if len(poems) + len(errors) == len(addresses):
            reactor.stop()

    for address in addresses:
        host, port = address
        d = get_poetry(host, port)
        d.addCallback(try_to_cummingsify)
        d.addCallbacks(got_poem, poem_failed)
        d.addBoth(poem_done)

    reactor.run()

  

因此,当从服务器上下载一首诗歌时,可能会出现如下情况:

1.打印诗歌的小写版本

2.打印 ”Cummingsify failed“并附上原始形式的诗歌

3.打印”The peom download failed”。

为了实现下面内容的效果,你可以打开多个服务器或开一个服务器而打开此程序次,直到你观察到所有不同的结果,当然也尝试一下去连接一个没有服务器值守的端口。

图19是我们给deferred添加回调后形成的callback/errback链:

图19 deferred中的回调链

注意到,"pass-throug”errback通过addCallback添加到链中。它会将任何其接收到的Failure传递给下一个errback(即poem_failed函数)。因此poem_failed函数可以处理来自get_poetry与try_to_commingsify两者的failure。下面让我们来分析下deferred可能会出现的激活情况,图20说明了我们能够下载到诗歌并且try_to_commingsify成功执行的路线图:

图20 成功下载到诗歌并且成功变换其格式

在这种情况中,没有回调执行失败,因此控制权一直在callback中流动。注意到poem_done收到的结果是None,这是因为它并没有返回任何值。如果我们想让后续的回调都能触及到诗歌内容,只要显式地让got_poem返回诗歌即可。

图21说明了我们在成功下载到诗歌后,但在try_to_cummingsify中抛出了GibberishError:

图21 成功下载到诗歌但出现了GibberishError

由于try_to_cummingsify回调抛出了GibberishError,所以控制权转移到了errback链,即poem_fail回调被调用并传入的捕获的异常作为其参数。

由于poem_failed并没有抛出获异常或返回一个Failure,因此在它执行完后,控制权又回到了callback链中。如果我们想让poem_fail完全处理好传进来的错误,那么返回一个None是再好不过的做法了。相反,如果我们只想让poem_failed采取一部分行动,但继续传递这个错误,那么我们需要改写poem_failed,即将参数err作为返回值返回。如此一来,控制权交给了下一个errback回调。

注意到,迄今为止,got_poem与poem_failed都不可能出现执行失败的情况,因此errback链上的poem_done是不可能被激活的。但在任何情况下这样做都是安全的,这体现了“防御式”编程的思想。比如在got_poem或poem_failed出现了bugs,那么这样做就不会让这个bugs的影响进入Twisted的核心代码区。鉴于上面的描述,可以看出addBoth类型于try/except中的finally语句。

下面我们再来看看第三种可能情况,即成功下载到诗歌但try_to_cummingsify抛出了VauleError,如图22:

图22:成功下载到诗歌当cummingsify执行失败

除了got_poem得到是原始式样的诗歌而不是小写版的外,与图20描述的情况完全相同。当然,控制权还是在try_to_cummingsif中进行了转移,即使用了try/except捕获了ValueError并返回了原始式样的诗歌。而这一切deferred并不知晓。

最后,我们来看看当试图连接一个无服务器值守的端口会出现什么情况,如图23所示:

图23 连接服务器失败

由于poem_failed返回了一个None,因此控权又回到了callback链中。

版本5.1

在版本5.0中我们使用普通的try/except来捕获try_to_cummingsify中的异常,而没有让deferred来捕获这个异常。这其实并没有什么错误,但下面我们将采取一种新的方式来处理异常。

设想一下,我们让deferred来捕获 GibberishError 与ValueError 异常,并将其传递到errback链中进行处理。如果要保留原有的行为,那么需要下面的errback来判断错误类型是否为Valuerror,如果是,那么返回原始式样的诗歌,这样一来,控制权再次回到callback链中并将原始式样的诗歌打印出来。

但有一个问题:errback并不会得到原始诗歌内容 。它只会得到由cummingsify抛出的vauleError异常。为了让errback处理这个错误,我们需要重新设计它来接收到原始式样的诗歌。

一种方法是改变cummingsify以让异常信息中包含原始式样的诗歌。这也正是我们在5.1版本中做的,其代码实现在twisted-client-5/get-poetry-1.py中。我们改写ValueError异常为CannotCummingsify异常,其能将诗歌作为其第一个参数来传递。

如果cummingsify中外部模块中一个真实存在的函数,那么其最好是通过另一个函数来捕获非GibberishError并抛出一个CannotCummingsify异常。这样,我们的poetry_main就成为:

def poetry_main():
    addresses = parse_args()
    from twisted.internet import reactor
    poems = []
    errors = []

    def cummingsify_failed(err):
        if err.check(CannotCummingsify):
            print ‘Cummingsify failed!‘
            return err.value.args[0]
        return err

    def got_poem(poem):
        print poem
        poems.append(poem)

    def poem_failed(err):
        print >>sys.stderr, ‘The poem download failed.‘
        errors.append(err)

    def poem_done(_):
        if len(poems) + len(errors) == len(addresses):
            reactor.stop()

    for address in addresses:
        host, port = address
        d = get_poetry(host, port)
        d.addCallback(cummingsify)
        d.addErrback(cummingsify_failed)
        d.addCallbacks(got_poem, poem_failed)
        d.addBoth(poem_done)

而新的deferred结构如图24所示:

图24:版本5.1的deferrd调用链结构

来看看cummingsify_failed的errback回调:

def cummingsify_failed(err):
    if err.check(CannotCummingsify):
        print ‘Cummingsify failed!‘
        return err.value.args[0]
    return err

我们使用了Failure中的check方法来确认嵌入在Failure中的异常是否是CannotCummingsify的实例。如果是,我们返回异常的第一个参数(即原始式样诗歌)。因此,这样一来返回值就不是一个Failure了,控制权也就又回到callback链中了。否则(即异常不是CannotCummingsify的实例),我们返回一个Failure,即将错误传递到下一个errback中。

图25说明了当我们捕获一个CannotCummingsify时的调用过程:

图25:捕获一个CannotCummingsify异常

因此,当我们使用deferrd时,可以选择使用try/except来捕获异常,也可以让deferred来将异常传递到errback回调链中进行处理。

总结:

在这个部分,我们增强了客户端的Deferred的功能,实现了异常与结果在callback/errback链中“路由”。(你可以将各个回调看作成路由器,然后根据传入参数的情况来决定其返回值进入下一个stage的哪条链,或者说控制权进入下一个stage的哪个类型的回调)。虽然示例程序是虚构出来的,但它揭示了控制权在deferred的回调链中交错传递具体方向依赖于返回值的类型。

那我们是不是已经对deferred无所不知了?不,我们还会在下面的部分继续讲解deferred的更多的功能。但在第十一部分,我们先不讲这部分内容,而是实现我们的Twisted版本的诗歌下载服务器。

时间: 2024-10-14 16:17:43

第十部分:增强defer功能的客户端的相关文章

AWK文本处理增强shell功能--AWK完全手册

AWK是一种优良的文本处理工具.它不仅是 Linux 中也是任何环境中现有的功能最强大的数据处理引擎之一. 本文主要摘录池中龙写的Unixawk使用手册(第二版),对其中内容稍微改动.感谢作者的分享. 目 录 1 0作者的话 2 1awk的调用方式 3 2awk的语法 4 3awk的记录.字段与内置变量 5 4awk的内置函数 5 5在命令行使用awk 6 6awk的变量 7 7运算与判断 7 8awk的流程控制 8 8.1BEGIN和END: 8 8.2流程控制语句 9 8.2.1if...e

Android开发:app工程集成银联支付功能(客户端)

Android开发:app工程集成银联支付功能(客户端) email:[email protected] 上一篇博文完成了服务器端的集成,可参考: Android开发:app工程集成银联支付功能(服务器端).这一篇博文完成客户端的集成. 一.功能描述 银联支付流程如下所示: 上一篇尝试了tn的获取,本篇将跑通整个流程. 二.实现部分 先说一下我的IDE是as(Android Studio)+win7 64位 2.1配置,依旧是配置 按照官方说明文档,就可以完成,我在这里贴上结构图,因为as的特殊

namespace javascript ajaxform 功能以及客户端js自动验证

Ns.UI.AjaxForm = function () {     Ns.UI.Control.apply(this, arguments);     this.onError = null;     this.onSuccess = null;     this.onBeforSend = null;     this.onComplete = null;     this.successFn = "";     this.validateFn = "";   

WCF技术剖析之十:调用WCF服务的客户端应该如何进行异常处理

原文:WCF技术剖析之十:调用WCF服务的客户端应该如何进行异常处理 在前面一片文章(服务代理不能得到及时关闭会有什么后果?)中,我们谈到及时关闭服务代理(Service Proxy)在一个高并发环境下的重要意义,并阐明了其根本原因.但是,是否直接调用ICommunicationObject的Close方法将服务代理关闭就万事大吉了呢?事情远不会这么简单,这其中还会涉及关于异常处理的一些操作,这就是本篇文章需要讨论的话题. 一.异常的抛出与Close的失败 一般情况下,当服务端抛出异常,客户客户

C#中关于增强类功能的几种方式

C#中关于增强类功能的几种方式 本文主要讲解如何利用C#语言自身的特性来对一个类的功能进行丰富与增强,便于拓展现有项目的一些功能. 拓展方法 扩展方法被定义为静态方法,通过实例方法语法进行调用.方法的第一个参数指定该方法作用于哪个类型,并且该参数以 this 修饰符为前缀.仅当使用 using 指令将命名空间显式导入到源代码中之后,扩展方法才可使用. namespace Extensions { public static class StringExtension { public stati

菜鸟学Android笔记(三十二):Request获取客户端的信息

一.request的概念及结构 1.概念 request对象是从客户端向服务器发出请求,包括用户提交的信息以及客户端的一些信息.客户端可通过HTML表单或在网页地址后面提供参数的方法提交数据,然后通过request对象的相关方法来获取这些数据.request的各种方法主要用来处理客户端浏览器提交的请求中的各项参数和选项 2.结构 request ServletRequest -- 通用request,提供一个request应该具有的最基本的方法 | |--HttpServletRequest -

二十 Filter&自动登录功能

Filter过滤器 过滤器,其实就是对客户端发出来的请求进行过滤,浏览器发出,然后服务器用Servelt处理.在中间就可以过滤,起到的是拦截的作用. 不仅仅作用于客户端请求,而且过滤服务器响应 作用: 对一些敏感词汇进行过滤 统一设置编码 自动登录 如何使用Filter? 新建一个类,实现Filter接口 注册过滤器,在web.xml中配置filter,url建议为/* chain.doFilter(request, response);//是否连接下一个过滤器,也就是说,过滤器3是否放行,让后

青蛙学Linux—Zabbix Web使用之Zabbix发现功能②主动客户端自动注册

主动客户端自动注册功能是Zabbix Agent主动向Zabbix Server进行注册.该功能适用于特定的环境中,如当我们无法确定新增主机的IP地址段时就可以使用该功能. 实现主动客户端自动注册功能,需要两个步骤:1.在Zabbix Agent的配置文件中添加元数据:2.在Zabbix Web中配创建一个动作. 这里以向当前的监控架构中添加一台新的主机(主机D)来演示如何实现主动客户端自动注册功能. 新添加的主机配置如下: 操作系统:CentOS 6.10 IP:192.168.0.61 Za

.Net界面开发控件DevExpress Winforms v19.2发布!增强图表功能

DevExpress Winforms Controls 内置140多个UI控件和库,完美构建流畅.美观且易于使用的应用程序.无论是Office风格的界面,还是分析处理大批量的业务数据,DevExpress WinForms都能轻松胜任!DevExpress Winforms v19.2日前正式发布啦!v19.2中发布了增强了Charting.Accordion性能等,欢迎立即下载v19.2体验哦! DevExpress Winforms v19.2正式版下载 全新的Gantt (CTP) Wa