文档章节

(转) Twisted : 第八部分 使用Deferred的诗歌下载客户端

水果糖
 水果糖
发布于 2016/01/27 13:21
字数 2067
阅读 12
收藏 0
点赞 1
评论 0

客户端4.0

我们已经对deferreds有些理解了,现在我们可以使用它重写我们的客户端。你可以在twisted-client-4/get-poetry.py看到它的实现。

这里的get_poetry已经再也不需要callbackerrback参数了。相反,返回了一个用户可能根据需要添加callbackserrbacks的新deferred

def get_poetry(host, port):
    """
    Download a poem from the given host and port. This function
    returns a Deferred which will be fired with the complete text of
    the poem or a Failure if the poem could not be downloaded.
    """
    d = defer.Deferred()
    from twisted.internet import reactor
    factory = PoetryClientFactory(d)
    reactor.connectTCP(host, port, factory)
    return d


这里的工厂使用一个deferred而不callback/errback对来初始化。一旦我们获取到poem后或者没有连接到服务器上,deferred就会以返回一首诗歌或一个failure的被激活。

 

class PoetryClientFactory(ClientFactory): 
    protocol = PoetryProtocol 
    def __init__(self, deferred):
        self.deferred = deferred
    
    def poem_finished(self, poem):
        if self.deferred is not None:
            d, self.deferred = self.deferred, None 
        d.callback(poem)
    def clientConnectionFailed(self, connector, reason):
        if self.deferred is not None:
            d, self.deferred = self.deferred, None
        d.errback(reason)

注意我们在deferred被激活后是如何销毁其引用的。这种方式普便存在于Twisted的源代码中,这样做可以保证我们不会激活一个deferred两次。这也为Python的垃圾回收带来的方便。

这里仍然不用去改变poetryProtocol。我们只需要更新poetry_main函数即可:

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

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

def poem_failed(err):
    print >>sys.stderr, 'Poem failed:', err
    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.addCallbacks(got_poem, poem_failed)
    d.addBoth(poem_done) 
    
reactor.run() 

for poem in poems: 
    print poem

注意我们是如何利用deferred的回调链在不考虑两个主要的callbackerrback回调外,重构poem_done调用的。

由于deferredTwisted大量被使用,使用小写字母d来表示当前正在工作中的deferred已经成为惯例。


讨论

新版本的客户端与我们前面的同步版本的客户端一样,get_poetry得到的参数都是诗歌下载服务器的地址。同步版本返回的是诗歌内容,而异步版本返回的却是一个deferred。返回一个deferredTwistedAPIs或用Twisted写的程序常见的,这样一来我们可以这样来理解deferred

一个Deferred代表了一个“异步的结果”或者“结果还没有到来”

在图13中可以更加清晰地表达出两者之间的不同:

第八部分:使用Deferred的诗歌下载客户端

13:同步 VS 异步

异步函数返回一个deferred,对用户意味着:

我是一个异步函数。不管你想要什么,可能现在马上都得不到。但当结果来到时,我会激活这个deferredcallback链并返回结果。或者当出错时,相应地激活errback链并返回出错信息。

当然,这个函数是不能随意激活这个deferred的,因为它已经返回了。但这个函数已经启动了一系列事件,这些事件最终将会激活这个deferred

因此,deferred是为适应异步模式的一种延迟函数返回的方式。函数返回一个deferred意味着其是异步的,代表着将来的结果,也是对将来能够返回结果的一种承诺。

同步函数也能返回一个deferred,因此严格点说,返回deferred只说可能是异步的。我们会在将来的例子中看到同步函数返回deferred

由于deferred的行为已经很好的定义与理解,因此在实现自己的API时返回一个deferred更容易让其它的Twisted程序理解你的代码。如果没有deferred,可能每个人写的模块都使用不同的方式来处理回调。这要一来就增加了相互理解的工作量。


当你使用Deferred时,你仍然在使用回调,它们仍然由reactor来调用。

当首次学习Twisted时,经常犯的一个错误就是:会给deferred增加一些它本身不能实现的功能。尤其是:经常假设在deferred上添加一个函数就可以使其变成异步函数。这可能会让你产生这样的想法:在Twisted 中可以通过将os.system的函数添加到deferred的回调链中。

我认为,这可能是没有弄清楚异步编程的原因才产生这样的想法。由于Twisted代码使用了大量的deferred但却很少会涉及到reactor,可能会认为deferred做了大部分工作。如果你是从开始阅读这个系列的,你就会知道事情远不是这样。虽然Twisted是由众多部分组合在一起来工作的,但实现异步的主要工作都是由reactor来完成的。Deferred是一个很好的抽象概念,但前面几个例子中的客户端我们却没有使用它,而reactor却都用到了。

来看看我们第一个回调激活时的跟踪栈信息。运行twisted-client-4/get-poetry-stack.py让其连接你打开的服务器:

File "twisted-client-4/get-poetry-stack.py", line 129, in
poetry_main()
File "twisted-client-4/get-poetry-stack.py", line 122, in poetry_main
reactor.run() ... # some more Twisted function calls
protocol.connectionLost(reason) 
File "twisted-client-4/get-poetry-stack.py", line 59, in connectionLost 
self.poemReceived(self.poem) 
File "twisted-client-4/get-poetry-stack.py", line 62, in poemReceived
self.factory.poem_finished(poem)
File "twisted-client-4/get-poetry-stack.py", line 75, in poem_finished
d.callback(poem) # here's where we fire the deferred 
... # some more methods on Deferreds
File "twisted-client-4/get-poetry-stack.py", line 105, in got_poem
traceback.print_stack()

这很像版本2.0的跟踪栈,图14可以很好地说明具体的调用关系:


第八部分:使用Deferred的诗歌下载客户端



14 deferred的回调

这很类似于我们前面的Twisted客户端,虽然这张图的调用关系并不清晰而会你摸不着头脑。但我们先不深入分析这张图。有一个细节并没有在这张图上反映出来:callback链直到第二个回调poem_done激活前才将控制权还给reactor

通过使用deferred,我们在由Twisted中的reactor启动的回调中加入了一些自己的东西,但我们并没有改变异步程序的基础架构。回忆下回调编程的特点:

1.在一个时刻,只会有一个回调在运行

2.reactor运行时,那我们自己的代码则得不到运行

3,反之则反之

4.如果我们的回调函数发生阻塞,那么整个程序就跟着阻塞掉了

在一个 deferred上追加一个回调并不会改变上面这些实事。尤其是,第4 条。因此当一个deferred激活时被阻塞,那么整个Twisted就会陷入阻塞中。因此我们会得到如下结论:

Deferred只是解决回调函数管理问题的一种解决方案。它并不一种替代回调方式也不能将阻塞式的回调变成非阻塞式回调的。

我通过构建一个添加阻塞式回调的deferred来验证最后一点。验证代码文件为twisted-deferred/defer-block.py。第二个callback通过使用time.sleep来达到阻塞的效果。如果你运行该代码来观察打印信息顺序时,你会发现deferred中阻塞回调仍然会阻塞掉。


总结

函数通过返回一个Deferred,向使用者暗示“我是采用异步方式的”并且当结果到来时会使用一种特殊的机制(在此处添加你的callbackerrback来获得返回结果。Defered被广泛地运用在Twisted的每个角落,当你浏览Twisted源码时你就会不停地遇到它。

4.0版本客户端是第一个使用DeferredTwisted版的客户端,其使用方法为在其异步函数中返回一个deferred来。可以使用一些TwistedAPIs来使客户端的实现更加清晰些,但我觉得它能够很好地体现出一个简单的Twisted程序是怎么写的了,至少对于客户端可以如此肯定。事实上,后面我们会重构我们的服务器端。

但我们对Deferred的讲解还没有结束。使用如此少量的代码,Deferred就能提供如此之多的功能。我们将在第9部分探讨其更多的功能和功能背后的动机。


本文转载自:http://blog.sina.com.cn/s/blog_704b6af70100py9n.html

共有 人打赏支持
水果糖
粉丝 15
博文 156
码字总数 51701
作品 0
深圳
程序员
(转) Twisted : 第十四部分 Deferred用于同步环境

介绍 这部分我们要介绍Deferred的另外一个功能。便于讨论,我们设定如下情景:假设由于众多的内部网请求一个外部诗歌下载服务器,但由于这个外部下载服务器性能太差或请求负荷太重。因此,我...

水果糖
2016/01/27
12
0
(转) Twisted :第七部分 小插曲,Deferred

回调函数的后序发展 在第六部分我们认识这样一个情况: 回调是Twisted异步编程中的基础。除了与reactor交互外,回调可以安插在任何我们写的Twisted结构内。因此在使用Twisted或其它基于react...

水果糖
2016/01/27
14
0
(转) Twisted :第十八部分 Deferreds 全貌

简介 在上一个部分,我们学习了使用生成器构造顺序异步回调的新方法.这样,包括 ,我们现在有两种将异步操作链接在一起的方法. 有时,然而,我们需要"并行"的运行一组异步操作.由于Twisted是单线程...

水果糖
2016/01/27
9
0
(转) Twisted :第十部分 增强defer功能的客户端

现在我们将要向诗歌下载客户端添加一些新的处理逻辑,包括在第九部分提到要添加的功能。不过,首先我要说明一点:我并不知道如何实现Byronification引擎。那超出了我的编程能力范围。取而代之...

水果糖
2016/01/27
10
0
(转) Twisted : 第十二部分 改进诗歌下载服务器

新的服务器实现 这里我们要新写一个Twisted版的服务器。然后,再来讨论一些Deferred的新功能。 在第九、十部分,我们提出了诗歌转换引擎这个概念。由于其实现太过简单,因此我们用随机选择来...

水果糖
2016/01/27
12
0
(转) Twisted : 第九部分 第二个小插曲,Deferred

更多关于回调的知识 稍微停下来再思考一下回调的机制。尽管对于以Twisted方式使用Deferred写一个简单的异步程序已经非常了解了,但Deferred提供更多的是只有在比较复杂环境下才会用到的功能。...

水果糖
2016/01/27
7
0
(转) Twisted :第十九部分 改变之前的想法

简介 Twisted是一个正在进展的项目,它的开发者会定期添加新的特性并且扩展旧的特性. 随着Twisted 10.1.0发布,开发者向 类添加了一个新的特性—— ——这正是我们今天要研究的. 异步编程将请求...

水果糖
2016/01/27
33
0
(转) Twisted : 第十三部分 使用Deferred新功能实现新客户端

介绍 回忆下第10部分中的客户端5.1版。客户端使用一个Deferred来管理所有的回调链,其中包括一个格式转换引擎的调用。在那个版本中,这个引擎的实现是同步的。(即等待其执行再切到其它函数或...

水果糖
2016/01/27
13
0
(转) Twisted :第十一部分 改进诗歌下载服务器

诗歌下载服务器 到目前为止,我们已经学习了大量关于诗歌下载客户端的Twisted的知识,接下来,我们使用Twisted重新实现我们的服务器端。利益于Twisted的抽象机制,接下来你会发现我们前面已经...

水果糖
2016/01/27
7
0
(转) Twisted :第六部分 抽象地利用Twisted

打造可以复用的诗歌下载客户端 我们在实现客户端上已经花了大量的工作。最新版本的(2.0)客户端使用了Transports,Protocols和Protocol Factories,即整个Twisted的网络框架。但仍有大的改进...

水果糖
2016/01/27
5
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

实现异步有哪些方法

有哪些方法可以实现异步呢? 方式一:java 线程池 示例: @Test public final void test_ThreadPool() throws InterruptedException { ScheduledThreadPoolExecutor scheduledThre......

黄威
今天
0
0
linux服务器修改mtu值优化cpu

一、jumbo frames 相关 1、什么是jumbo frames Jumbo frames 是指比标准Ethernet Frames长的frame,即比1518/1522 bit大的frames,Jumbo frame的大小是每个设备厂商规定的,不属于IEEE标准;...

六库科技
今天
0
0
牛客网刷题

1. 二维数组中的查找(难度:易) 题目描述 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入...

大不了敲一辈子代码
今天
0
0
linux系统的任务计划、服务管理

linux任务计划cron 在linux下,有时候要在我们不在的时候执行一项命令,或启动一个脚本,可以使用任务计划cron功能。 任务计划要用crontab命令完成 选项: -u 指定某个用户,不加-u表示当前用...

黄昏残影
昨天
0
0
设计模式:单例模式

单例模式的定义是确保某个类在任何情况下都只有一个实例,并且需要提供一个全局的访问点供调用者访问该实例的一种模式。 实现以上模式基于以下必须遵守的两点: 1.构造方法私有化 2.提供一个...

人觉非常君
昨天
0
0
《Linux Perf Master》Edition 0.4 发布

在线阅读:https://riboseyim.gitbook.io/perf 在线阅读:https://www.gitbook.com/book/riboseyim/linux-perf-master/details 百度网盘【pdf、mobi、ePub】:https://pan.baidu.com/s/1C20T......

RiboseYim
昨天
1
0
conda 换源

https://mirrors.tuna.tsinghua.edu.cn/help/anaconda/ conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/conda config --add channels https://mir......

阿豪boy
昨天
1
0
Confluence 6 安装补丁类文件

Atlassian 支持或者 Atlassian 缺陷修复小组可能针对有一些关键问题会提供补丁来解决这些问题,但是这些问题还没有放到下一个更新版本中。这些问题将会使用 Class 类文件同时在官方 Jira bug...

honeymose
昨天
0
0
非常实用的IDEA插件之总结

1、Alibaba Java Coding Guidelines 经过247天的持续研发,阿里巴巴于10月14日在杭州云栖大会上,正式发布众所期待的《阿里巴巴Java开发规约》扫描插件!该插件由阿里巴巴P3C项目组研发。P3C...

Gibbons
昨天
1
0
Tomcat介绍,安装jdk,安装tomcat,配置Tomcat监听80端口

Tomcat介绍 Tomcat是Apache软件基金会(Apache Software Foundation)的Jakarta项目中的一个核心项目,由Apache、Sun和其他一些公司及个人共同开发而成。 java程序写的网站用tomcat+jdk来运行...

TaoXu
昨天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部