Introduction

在这一部分我们将要学习deferred 类的另外的一个方面.为了促进讨论,我们要为我们的poetry service增加一个server.假设我们有大量的内部的client 想要连接一个相同的外部的server.假设这个server已经很慢而且已经负载很高了.我们不想再让server上连接更多的client 了.

所以我们会创建一个缓存代理服务器.当一个client 连接到proxy的时候,这个proxy或者从外部的server获取到一首诗或者就返回一个之前已经缓存了的内容.我们可以让我们的client 都连接proxy,我们的外部的server 的负载就会很小.我们可以用图片三十来描述这个过程:


图片三十

思考一下当一个client连接到proxy 之后会发生什么,假如这个proxy 的缓存是不存在的,这个proxy必须异步等待外部的server 返回一个结果然后才能返回client.到目前为止还不错,我们已经知道怎样去处理返回deferred 的异步的函数.另一方面,假如在缓存中已经有了一个一首诗,这个proxy 会把它立即返回,一点也不用等待.所以proxy获取一首诗的内容可以是同步的或者是异步的.

所以 我们能做些什么假如我们有一个有时异步有时同步的函数?twisted 提供了很多选项,并且它们依据deferred 的一个我们没有讲的特色:你可以在你返回deferred之前触发它.

这个是管用的,因为尽管你不能触发一个deferred 两次,但是你可以在deferred 触发之后向deferred 中增加callbacks 和 errbacks.当你这样做的时候,deferred 会继续的触发 callback/errback 链 从上次它离开的地方.一个很重要的一点是一个已经触发的deferred 可以立即触发新假如的callback.

图片三十一展示了一个已经被触发的deferred:


图片三十一

如果我们现在向其中加入一对callback/errback,这个deferred 会立即的触发新加入的callback,就像图片三十二:


图片三十二

我们测试这个deferred 的新特色通过代码twisted-deferred/defer-11.py.试着运行一下并看看deferred 被触发之后又加入callback 之后会发生什么.注意在第一个例子中每个新的callback是怎样被立即触发的.

第二个例子展示了我们怎样pause() 一个deferred不让它立即触发callback的.当我们都准备好的时候,我们可以用unpause().其实暂停deferred 的原理和 当一个callback 返回deferred 导致外部的deferred 暂停的原理是一样的.

Proxy 1.0

现在让我们看一下第一版的poetry proxy –twisted-server-1/poetry-proxy.py,因为这个proxy 同时扮演了client 和 server 的角色,它有两对 Protocol/Factory.一个用来为poetry 服务,另一个用来从外部的server 获取诗歌的内容.我们就不看为client 服务的protocol/factory 了,和以前的版本一样.

让我们来看 ProxyService,proxy中的server-side protocol 利用它来从外部的server获取一首诗:

class ProxyService(object):

poem = None # the cached poem

def __init__(self, host, port):
        self.host = host
        self.port = port

def get_poem(self):
        if self.poem is not None:
            print 'Using cached poem.'
            return self.poem

print 'Fetching poem from server.'
        factory = PoetryClientFactory()
        factory.deferred.addCallback(self.set_poem)
        from twisted.internet import reactor
        reactor.connectTCP(self.host, self.port, factory)
        return factory.deferred

def set_poem(self, poem):
        self.poem = poem
        return poem

重要的方法是get_poem.假如在缓存里已经有一首诗存在,直接返回.如果没有的话,我们向外部的server 发起一个连接并返回一个deferred,如果等待的诗来到则触发deferred.get_poem 是一个只有一部分时间是异步的.

怎样来处理那样的一个函数呢?让我们来看一下server-side protocol/factory :

class PoetryProxyProtocol(Protocol):

def connectionMade(self):
        d = maybeDeferred(self.factory.service.get_poem)
        d.addCallback(self.transport.write)
        d.addBoth(lambda r: self.transport.loseConnection())

class PoetryProxyFactory(ServerFactory):

protocol = PoetryProxyProtocol

def __init__(self, service):
        self.service = service

这个factory 是很简单的,它只保存了一个proxy service 的引用,这样可以让protocol 实例可以调用get_poem 方法.protocol 是核心所在.它没有直接的调用get_poem,而是使用了一个twisted.internet.defer 的封装—maybeDeferred.

maybeDeferred 函数拿到一个函数的引用,并加上了一些参数,maybeDeferred 会最终调用这个函数,并且做如下的工作:

如果这个函数返回了一个deferred,maybeDeferred 也返回这个deferred,或者
    假如这个函数返回了一个Failure,maybeDeferred 返回一个已经被触发的deferred ,并带着failure参数,或者
    假如这个函数返回了一个正常的值,maybeDeferred返回一个已经被触发的deferred,并带着这个正常的值作为参数,或者
    假如这个函数抛出了一个错误,maybeDeferred会返回一个已经被触发的deferred,并带着由这个错误转化来的failure作为参数

换句话说,从maybeDeferred 返回的值一定是一个deferred,即使你传递过去的函数不会返回deferred.这就让我们可以安全的调用一个同步的函数,并把它当作一个返回deferred异步的函数.

注意一:这里仍有一点不一样,被一个同步的函数返回的deferred 是已经被触发过的,所以任何的你加入的callback 和errback 都会被立即调用,而不是在一些reactor loop 的迭带之后.
注意二:也许给一个一定会返回deferred 的函数命名为maybeDeferred 不是一个特别好的选择.

一但这个protocol 有了一个真正的deferred,它可以增加一些callback把诗送到client,并关闭相应的连接.这个就是我们的第一个poetry proxy.

Running the Proxy

要测试我们的代理的话,先开启一个poetry server,像下面这样:

python twisted-server-1/fastpoetry.py --port 10001 poetry/fascination.txt

然后开启一个proxy server:

python twisted-server-1/poetry-proxy.py --port 10000 10001

也就说proxy 运行在10000端口,poetry server 运行在10001端口.
下面你可以运行一个client 连接proxy:

python twisted-client-4/get-poetry.py 10000

我们使用了一个早期的没有poetry transformations 的client 版本.你可以看到一首诗出现在client 的窗口里,还有一些文字说明它正在从server 下载.如果你再运行client 一次,这个proxy 会告诉你它正在使用缓存起来的poem.

Proxy 2.0

我们前面已经说过,还有另外一种方法可以实现我们的需求.在Porxy 2.0 中有说明,代码见twisted-server-2/poetry-proxy.py.既然我们可以在返回deferred之前触发它,我们可以让proxy service 在缓存中已经存在这首诗的时候返回一个已经触发过的deferred.下面是proxy service 中get_poem 的新版本:

def get_poem(self):
    if self.poem is not None:
        print 'Using cached poem.'
        # return an already-fired deferred
        return succeed(self.poem)

print 'Fetching poem from server.'
    factory = PoetryClientFactory()
    factory.deferred.addCallback(self.set_poem)
    from twisted.internet import reactor
    reactor.connectTCP(self.host, self.port, factory)
    return factory.deferred

这个defer.succeed 函数是创建一个已经触发的deferred并返回一个值的很便捷的方法.查看一下它的实现你会发现它就是创建一个deferred ,并用callback()触发 的封装.如果我们想返回一个已经失败了的deferred 我们可以用defer.fail.

在这个版本中,因为get_poem 已经返回了一个deferred,protocol 类不再需要maybeDeferred:

class PoetryProxyProtocol(Protocol):

def connectionMade(self):
        d = self.factory.service.get_poem()
        d.addCallback(self.transport.write)
        d.addBoth(lambda r: self.transport.loseConnection())

除了这两个地方的变化之外,其他的没什么变化了.你可以像上面的方法一样来运行它.

Summary

在这一部分我们学到了怎样deferred 在被返回之前被调用,因而我们可以在同步的程序使用它,我们有两种方法去实现它:

我们可以使用maybeDeferred来处理时而返回deferred 时而返回正常结果的函数
    我们可以用defer.succed 和 defer.fail 提前触发我们的deferred,所以我们的有时同步有时异步的函数可以总是返回deferred

我们可以使用他们中的任何一个方法.前一个强调了我们的函数不是总是异步的,而后一个让代码更简单.没有一个定论非要使用哪个.

两种方法都可以是因为我们可以向deferred中增加callback/errback 在它被触发之后.它也解了我们在第九部分提出的疑问.我们了解到在deferred中,不管是最后一个callback 或者errback 失败,错误会在deferred 被垃圾回收的时候才被报告出来.现在我们知道因为什么了–因为我们可以一直向一个deferred 对象中增加一个callback/errback 对,直到最后一个对deferred 的引用也消失了,twisted 才能认定这个错误没有被处理.

所以,这就是deferred了吗?我们已经知道deferred 的全部了吗? 对于大部分来说,是的.但是twisted 包含了很多我们还没有探寻到的很多种交替使用deferred 的方式.同时,twisted 的开发人员也在不停的增加新的特色.在将来的发布的版本中,deferred 会有更多的能力.我们会在以后的章节中讲到,但首先我们需要从deferred中休息一下,看一些twisted 的其他的方面.

----
20120821 16:08
运行 Proxy 1.0 是做为一个代理服务器,客户端是连接到这个 Proxy 1.0 上而不是外部的 server 上。如果 Proxy 1.0 中有缓存数据的话,将取到的数据通过 PretryProxyProtocol 中的 d.addCallback(self.transport.write) 发给先前的客户端。否则向外部的 server 发起一个连接用于取数据,再通过同样的方式发送给客户端。

twisted系列教程十四— pre-fireed deferred相关推荐

  1. twisted系列教程十九–cancel deferred

    Introduction twisted 是一个正在发展的项目,twisted 的开发者们会添加一些新的特色或者扩展旧的.随着twisted 10.1.0 的发布,开发者们增加了一个新的功能–取消,这 ...

  2. twisted系列教程十六–twisted守护进程

    Introduction 到目前为止我们写的server 还运行在一个终端里面,通过print 语句向外输出内容.开发的时候这样做是很有好处的,但是当你部署一个产品的时候这样就不好了.一个生产环境中的 ...

  3. twisted系列教程十–可以变化的诗

    Client 5.0 现在我们将要想我们的client中加入一些变形逻辑.但是首先我不得不说:我不知道怎样写一个Byronification 引擎,它超出我的能力范围了.做为替代,我会实现一个相对简单 ...

  4. Cobaltstrike系列教程(十四)网站克隆与邮件鱼叉钓鱼

    0x000-前言 有技术交流或渗透测试培训需求的朋友欢迎联系QQ/VX-547006660,需要代码审计.渗透测试.红蓝对抗网络安全相关业务可以咨询我 2000人网络安全交流群,欢迎大佬们来玩 群号8 ...

  5. twisted系列教程十五–测试twisted代码

    Introduction 在这个系列中我们也已经写了很多twisted 代码了,但目前为止我们忽略了一个很重要的事情-测试.你可能也一直在想我们怎样用一个同步的测试框架unitest来测试我们的异步的 ...

  6. twisted系列教程十二–为server 增加一个service

    One More Server 在第九部分和第十部分我们介绍了关于诗歌的变形引擎的想法,最后我们实现了cummingsifier,我们还让它抛出随机的异常来模拟错误.但是假如这个变形的引擎在另外一台服 ...

  7. twisted系列教程十八–异步操作的并行运行

    Introduction 在上一部分我们学习了一种新的用生成器来组织一系列异步callbacks 的方法.加上deferred,我们已经有两种组织异步操作的方法了. 有时候,我们想让一组异步操作并行的 ...

  8. Spring Boot2 系列教程(十四)CORS 解决跨域问题

    今天和小伙伴们来聊一聊通过CORS解决跨域问题. 同源策略 很多人对跨域有一种误解,以为这是前端的事,和后端没关系,其实不是这样的,说到跨域,就不得不说说浏览器的同源策略. 同源策略是由 Netsca ...

  9. akka学习教程(十四) akka分布式实战

    akka系列文章目录 akka学习教程(十四) akka分布式实战 akka学习教程(十三) akka分布式 akka学习教程(十二) Spring与Akka的集成 akka学习教程(十一) akka ...

最新文章

  1. Object.keys方法之详解
  2. 油品调和计算软件_海博柴油批发:调和密度的利润空间
  3. PowerDesigner中为Oracle添加自增id
  4. python长连接框架_python之websocket【长连接的实现】
  5. 角色管理与今日内容介绍
  6. bootstrap 输入错误提示_win7系统提示explorer.exe应用程序错误怎么办
  7. [crypto][ipsec] 简述ESP协议的sequence number机制
  8. 消息称苹果正开发基于自研ARM芯片的游戏主机
  9. 判断两个日期相差的天数
  10. BZOJ 1006: [HNOI2008]神奇的国度( MCS )
  11. 快速排序及快速选择问题
  12. Linux安装winetim简单教程,[转载]wine安装最新版TIM
  13. 波利亚《如何解题 How to Solve It》
  14. 如何用计算机画地形地貌图,地形图是如何绘制出来的
  15. 南佛罗里达大学计算机科学硕士,去南佛罗里达大学读硕士好吗
  16. python研究背景和意义_选题背景、目的及研究意义
  17. 谷歌浏览器历史记录查看很慢解决方案
  18. 美颜SDK是什么意思?美颜SDK可以用在哪些地方?
  19. 声网 Agora 的 2019
  20. B. Alyona and a Narrow Fridge 【 思维题 】

热门文章

  1. vue框架可以配合php做企业站,基于Vue和PHP打造前后端分离的通用管理系统(一)...
  2. 量子通信入门相关书籍
  3. 如何确认自己的电脑是否可以更新到win11
  4. STM32中GPIO_Mode--GPIO配置
  5. vs矩形框边框线显示被选中的区域;_条形码区域解码:Web小工具
  6. javaweb+C+asp毕业设计项目合集免费下载
  7. python的flask实现第三方登录怎么写_Python语言的Flask框架应用程序实现使用QQ账号登录的方法...
  8. Python笔记-安装python虚拟环境及配置opencv及通过opencv识别颜色
  9. Qt工作笔记-列表的分页显示(Qt Widgets框架)
  10. Linux学习笔记-子目录的支持