Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5120071
  • 博文数量: 921
  • 博客积分: 16037
  • 博客等级: 上将
  • 技术积分: 8469
  • 用 户 组: 普通用户
  • 注册时间: 2006-04-05 02:08
文章分类

全部博文(921)

文章存档

2020年(1)

2019年(3)

2018年(3)

2017年(6)

2016年(47)

2015年(72)

2014年(25)

2013年(72)

2012年(125)

2011年(182)

2010年(42)

2009年(14)

2008年(85)

2007年(89)

2006年(155)

分类: Python/Ruby

2011-11-20 23:59:31

Deferred:
提供了让程序查找非同步任务完成的一种方式,而在这时还可以做其他事情。当函数返回一个Deferred对象时,说明获得结果之前还需要一定时间。为了在任务完成时

获得结果,可以为Deferred指定一个事件处理器
非阻塞通讯:
当前有一个请求,当获得连接之后,需要进行数据库的读写操作,同时还有其他线程也等着连接:
那么可以讲当前获得连接后进行数据库操作的这个任务挂起来,然后直接去处理其他线程,当挂起的线程处理结果出来时候,直接返回一个结果就可以了。这样子节约

了资源,提高了效率;
需要为挂起的任务保持一个上下文环境的存储,就用defer来完成这个任务,之所以要保持上下文环境的存储是因为你的操作还没有结束,下面你还要去调用当前的任务

,那你肯定得有一个上下文的环境才可以的。利用defer保存当前任务的环境信息,通过定义callback函数来进行最后结果的回调。

Twisted使用Deferred对象来管理callback序列。作为Twisted库的“客户端”,应用程序将一连串函数添加到Deferred对象中,当异步请求的结果准备就绪时,这一连

串函数将被按顺序调用(这一连串函数被称为一个callback序列,或是一条callback链),一起添加的还有另外一连串函数,当异步请求出现错误的时候,他们将被调

用(称作一个errback序列,或是一条errback链)。异步库代码会在结果准备就绪时,调用第一个callback,或是在出现错误时,调用第一个errback,然后Deferred对

象就会将callback或errback的返回结果传递给链中的下一个函数。


Deferred解决的问题
Deferred被设计用来帮助解决第二类并发问题——非计算集中型任务,并且延迟时间是可以估计的。等待硬盘访问,数据库访问和网络访问的函数都属于这一类,尽管

时间延迟不尽相同。

Deferred被设计用来使Twisted程序可以无阻塞地等待数据,直到数据准备就绪。为了达到这个目的,Deferred为库与应用程序提供了一个简单的callback管理接口。库

可以通过调用Deferred.callback来把准备就绪的数据传回给应用程序,或者调用Deferred.errback来报告一个错误。应用程序可以按它们希望的顺序,设置结果处理逻

辑,以callback与errback的形式添加到Deferred对象中去。

使CPU尽可能的有效率,是Deferred与该问题的其他解决方案背后的基本思路。如果一个任务在等待数据,与其让CPU(以及程序本身!)眼巴巴地等着数据(对于进程

,这通常叫做“阻塞”),不如让程序同时执行些别的操作,并且同时留意着某些信号——一旦数据准备就绪,程序就可以(但不是立即——译者注)回到刚才的地方

继续执行。

在Twisted里,一个函数返回一个Deferred对象,意味着它给调用者一个信号:它在等待数据。当数据准备就绪后,程序就会激活那个Deferred对象的callback链,来处

理数据。

Deferred——数据即将到来的信号
在之前我们发送电子邮件的例子中,父函数调用了一个连接远程服务器的函数。异步性要求这个连接函数必须不等待结果而直接返回,父函数才可以做其他事情。可是

,父函数或者它的控制程序又是怎么知道连接尚未建立的呢?当连接建立后,它又是怎么使用连接的呢?

Twisted有一个对象可以作为这种情况的一个信号。连接函数返回一个twisted.internet.defer.Deferred对象,给出一个操作尚未完成的信号。

Deferred有两个目的。第一,它说“我是一个信号,只是通知你不管你刚才要我做的什么,结果还没有出来”。第二,你可以让Deferred在结果出来后执行你的东西。

 

callback
添加一个callback——这就是你让Deferred在结果出来后执行你东西的办法,也就是让Deferred在结果出来后调用一个方法。

有一个Twisted库函数返回Deferred,就是twisted.web.client.getPage(这是一个异步获取网页的函数。——译者注)。在这个例子里,我们调用了getPage——它返

回了一个Deferred,然后添加了一个callback来处理返回的页面内容——当然处理是发生在数据准备就绪之后:

from twisted.web.client import getPage

from twisted.internet import reactor

def printContents(contents):
    '''
    这就是“callback”函数,被添加到Deferred,当“承诺了一定会有的数据”准备就绪后,
    Deffered会调用它
    '''

    print "Deferred调用了printContents,内容如下:"
    print contents

    # 停止Twisted事件处理系统————这通常有更高层的办法
    reactor.stop()

# 调用getPage,它会马上返回一个Deferred————承诺一旦页面内容下载完了,
# 就会把他们传给我们的callback们
deferred = getPage('')

# 给Deferred添加一个callback————要求它在页面内容下载完后,调用printContents
deferred.addCallback(printContents)

# 启动Twisted事件处理系统,同样,这不是通常的办法
reactor.run()

添加两个callback是一种非常常见的Deferred用法。第一个callback的返回结果会传给第二个callback:

from twisted.web.client import getPage

from twisted.internet import reactor

def lowerCaseContents(contents):
    '''
    这是一个“callback”函数,被添加到Deferred,当“承诺了一定会有的数据”准备就绪后,
    Deffered会调用它。它把所有的数据变成小写
    '''

    return contents.lower()

def printContents(contents):
    '''
    这是一个“callback”函数,在lowerCaseContents之后被添加到Deferred,
    Deferred会把lowerCaseContents的返回结果作为参数,调用这个callback
    '''

    print contents
    reactor.stop()

deferred = getPage('')

# 向Deferred中添加两个callback————让Deferred在页面内容下载完之后执行
# lowerCaseContents,然后将其返回结果作为参数,调用printContents
deferred.addCallback(lowerCaseContents)
deferred.addCallback(printContents)

reactor.run()

错误处理:errback
正如异步函数会在其结果产生之前返回,在有可能检测到错误之前返回也是可以的:失败的连接,错误的数据,协议错误,等等。正如你可以将callback添加到

Deferred,你也可以将错误处理逻辑(“errback”)添加到Deferred,当出现错误,数据不能正常取回时,Deferred会调用它:

from twisted.web.client import getPage

from twisted.internet import reactor

def errorHandler(error):
    '''
    这是一个“errback”函数,被添加到Deferred,当出现错误事件是,Deferred将会调用它
    '''

    # 这么处理错误并不是很实际,我们只是把它打出来:
    print "An error has occurred: <%s>" % str(error)
    # 然后我们停止整个处理过程:
    reactor.stop()

def printContents(contents):
    '''
    这是一个“callback”函数,被添加到Deferred,Deferred会把页面内容作为参数调用它
    '''

    print contents
    reactor.stop()

# 我们请求一个不存在的页面,来演示错误链
deferred = getPage('does-not-exist')

# 向Deferred添加callback,以处理页面内容
deferred.addCallback(printContents)

# 向Deferred添加errback,以处理任何错误
deferred.addErrback(errorHandler)

reactor.run()

阅读(904) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~