twisted系列教程十四— pre-fireed deferred
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相关推荐
- twisted系列教程十九–cancel deferred
Introduction twisted 是一个正在发展的项目,twisted 的开发者们会添加一些新的特色或者扩展旧的.随着twisted 10.1.0 的发布,开发者们增加了一个新的功能–取消,这 ...
- twisted系列教程十六–twisted守护进程
Introduction 到目前为止我们写的server 还运行在一个终端里面,通过print 语句向外输出内容.开发的时候这样做是很有好处的,但是当你部署一个产品的时候这样就不好了.一个生产环境中的 ...
- twisted系列教程十–可以变化的诗
Client 5.0 现在我们将要想我们的client中加入一些变形逻辑.但是首先我不得不说:我不知道怎样写一个Byronification 引擎,它超出我的能力范围了.做为替代,我会实现一个相对简单 ...
- Cobaltstrike系列教程(十四)网站克隆与邮件鱼叉钓鱼
0x000-前言 有技术交流或渗透测试培训需求的朋友欢迎联系QQ/VX-547006660,需要代码审计.渗透测试.红蓝对抗网络安全相关业务可以咨询我 2000人网络安全交流群,欢迎大佬们来玩 群号8 ...
- twisted系列教程十五–测试twisted代码
Introduction 在这个系列中我们也已经写了很多twisted 代码了,但目前为止我们忽略了一个很重要的事情-测试.你可能也一直在想我们怎样用一个同步的测试框架unitest来测试我们的异步的 ...
- twisted系列教程十二–为server 增加一个service
One More Server 在第九部分和第十部分我们介绍了关于诗歌的变形引擎的想法,最后我们实现了cummingsifier,我们还让它抛出随机的异常来模拟错误.但是假如这个变形的引擎在另外一台服 ...
- twisted系列教程十八–异步操作的并行运行
Introduction 在上一部分我们学习了一种新的用生成器来组织一系列异步callbacks 的方法.加上deferred,我们已经有两种组织异步操作的方法了. 有时候,我们想让一组异步操作并行的 ...
- Spring Boot2 系列教程(十四)CORS 解决跨域问题
今天和小伙伴们来聊一聊通过CORS解决跨域问题. 同源策略 很多人对跨域有一种误解,以为这是前端的事,和后端没关系,其实不是这样的,说到跨域,就不得不说说浏览器的同源策略. 同源策略是由 Netsca ...
- akka学习教程(十四) akka分布式实战
akka系列文章目录 akka学习教程(十四) akka分布式实战 akka学习教程(十三) akka分布式 akka学习教程(十二) Spring与Akka的集成 akka学习教程(十一) akka ...
最新文章
- Object.keys方法之详解
- 油品调和计算软件_海博柴油批发:调和密度的利润空间
- PowerDesigner中为Oracle添加自增id
- python长连接框架_python之websocket【长连接的实现】
- 角色管理与今日内容介绍
- bootstrap 输入错误提示_win7系统提示explorer.exe应用程序错误怎么办
- [crypto][ipsec] 简述ESP协议的sequence number机制
- 消息称苹果正开发基于自研ARM芯片的游戏主机
- 判断两个日期相差的天数
- BZOJ 1006: [HNOI2008]神奇的国度( MCS )
- 快速排序及快速选择问题
- Linux安装winetim简单教程,[转载]wine安装最新版TIM
- 波利亚《如何解题 How to Solve It》
- 如何用计算机画地形地貌图,地形图是如何绘制出来的
- 南佛罗里达大学计算机科学硕士,去南佛罗里达大学读硕士好吗
- python研究背景和意义_选题背景、目的及研究意义
- 谷歌浏览器历史记录查看很慢解决方案
- 美颜SDK是什么意思?美颜SDK可以用在哪些地方?
- 声网 Agora 的 2019
- B. Alyona and a Narrow Fridge 【 思维题 】
热门文章
- vue框架可以配合php做企业站,基于Vue和PHP打造前后端分离的通用管理系统(一)...
- 量子通信入门相关书籍
- 如何确认自己的电脑是否可以更新到win11
- STM32中GPIO_Mode--GPIO配置
- vs矩形框边框线显示被选中的区域;_条形码区域解码:Web小工具
- javaweb+C+asp毕业设计项目合集免费下载
- python的flask实现第三方登录怎么写_Python语言的Flask框架应用程序实现使用QQ账号登录的方法...
- Python笔记-安装python虚拟环境及配置opencv及通过opencv识别颜色
- Qt工作笔记-列表的分页显示(Qt Widgets框架)
- Linux学习笔记-子目录的支持