全部博文(82)
分类: Python/Ruby
2010-04-08 17:28:53
Defer()的方法:addCallback()和callback()
之前对addCallback()、callback(),如何使用以及它们的工作原理一直弄不明白,只知道是回调机制,经过学习,总结如下:
Twisted中,reactor和defer是核心。Reactor是为程序运行建立全局循环;defer则是实现了回调机制。
Defer()类中,有一个变量self.called,这个很关键,决定着addCallback(func,*args,**kw)中能否执行所传入的函数func,而self.called是在callback()被设置的self.called=True。所以,要执行func(),就必须有一个callback(),而且只能有一个,测试过,有两个就报错。下面这段代码是报错的原因(self.called已经被赋值,在下面还可以从另一个角度看明白):
if self.called:
if self.debug:
if self._debugInfo is None:
self._debugInfo = DebugInfo()
extra = "\n" + self._debugInfo._getDebugTracebacks()
raise AlreadyCalledError(extra)
raise AlreadyCalledError
Defer()类中,有一个列表self.callbacks = [],保存的是addCallback()传入的函数和参数的,每调用一次,在self.callbacks中就多一项,可以保存很多组,可以多次调用addCallback()。经过多次调用,那各次调用的函数func()(各次不同或者相同)是否有联系呢?可以有,也可以没有。Func()执行时,所传入的参数不仅仅是addCallback()中的args,kw。实际的执行过程是这样的:
self.result = callback(self.result, *args, **kw)
#这里的callback()就是上面的func()
self.result是Defer()类的变量,最开始的值是由callback()传入的。通过循环,提取self.callbacks中的项,调用self.result = callback(self.result, *args, **kw),上一次的结果self.result作为下一项的第一个参数传入下一个函数,所以只需要第一次调用时需要外界传入参数。当然,没有参数也是可以的,但是callback()必须调用一次,因为self.called需要设置。这里也可以看出为什么callback()只能调用一次,因为参数只需要传入最初的一个就够了(这些都是个人猜想,非官方信息)。(如果想让callback()可以多次调用,也是可以的,修改defer.py文件中的_startRunCallbacks()。玩笑,这样做肯定有原因的)
回调机制,是让一件事自己去做,做好了之后再来通知我。
假设我们有三个函数main(),funA(),funB()).main()是主程序,有很多事要做,因为功能需要,funA()的运行必须是在funB()运行完之后。如果采用普通返回值的方式,是比较费时,而且效率不高的。我们如何让funB()运行完之后自动去执行funA()呢?回调机制可以解决。我们只要在funB()所有语句之后生成defer,然后调用defer.callback(),最后返回这个defer。而在main()函数中,在执行了d = funB()语句后,添加d.addCallback(funA,),就是把funA()添加到callbaks = []列表中,那样就会在funB()执行完后自动被执行。如果希望在funB()执行之后再执行多个动作,只要将那些动作(函数)添加到callbacks =[] 列表中即可,会按添加顺序执行。
如果在执行callbacks = []列表里的项出错时,那会发生什么呢?会转而执行addErrback()所添加的。
Each callback will have its result passed as the first
argument to the next; this way, the callbacks act as a
'processing chain'. Also, if the success-callback returns a L{Failure}
or raises an L{Exception}, processing will continue on the *error*-
callback chain.
上面这段是callback()函数的说明。