首先来看看,Deferred的__init__方法的参数:
def __init__(self, canceller=None):
直接分析
366 def cancel(self):
367 """
368 Cancel this L{Deferred}.
369
370 If the L{Deferred} has not yet had its C{errback} or C{callback} method
371 invoked, call the canceller function provided to the constructor. If
372 that function does not invoke C{callback} or C{errback}, or if no
373 canceller function was provided, errback with L{CancelledError}.
374
375 If this L{Deferred} is waiting on another L{Deferred}, forward the
376 cancellation to the other L{Deferred}.
377 """
378 if not self.called: # 如果deferrd还没有被激活,则有cancel开始执行下面的操作
379 canceller = self._canceller
380 if canceller: # 如果在Deferred函数时指定了参数
381 canceller(self) # 则把deferred本身当作参数传给那个函数
382 else: # 如果在生活Deferred实例时,没有指定参数
383 # Arrange to eat the callback that will eventually be fired
384 # since there was no real canceller.
385 self._suppressAlreadyCalled = 1 # 将这个值设为1 ,后续的回调都将会被"无视"
386 if not self.called: # 如果没被激活,这就说明,我们可以在canceller中,选择使用任何结果或错误自己激发 deferred (这样就会优先于 CancelledError 失败.
387 # There was no canceller, or the canceller didn't call
388 # callback or errback.
389 self.errback(failure.Failure(CancelledError())) # 调用errback,切记,如果有指定canceller的情况下,此时deferred已被激活,因为deferred只能被激活一次,如果后面还是有callback或errback,会报AlreadyCalledError异常
390 elif isinstance(self.result, Deferred): # 如果结果是个deferred(子deferred),则取消子deferred。
391 # Waiting for another deferred -- cancel it instead.
392 self.result.cancel()
请看代码:
from twisted.internet import defer def canceller(d): print "I need to cancel this deferred:",d def callback(res): print 'callback got:', res def errback(err): print 'errback got:', err d = defer.Deferred(canceller) d.addCallbacks(callback,errback) d.cancel() d.callback("ok") # 因为def canceller,cancel中有个errback,所以这里会报AlreadyCalledError异常
输出:
I need to cancel this deferred: <Deferred at 0xa957e8>
errback got: [Failure instance: Traceback (failure with no frames): <class 'twisted.internet.defer.CancelledError'>:
]
Traceback (most recent call last):
File "t.py", line 18, in <module>
d.callback("ok")
File "/usr/lib/python2.7/dist-packages/twisted/internet/defer.py", line 362, in callback
self._startRunCallbacks(result)
File "/usr/lib/python2.7/dist-packages/twisted/internet/defer.py", line 451, in _startRunCallbacks
raise AlreadyCalledError
twisted.internet.defer.AlreadyCalledError
如果代码是:
from twisted.internet import defer def canceller(d): print "I need to cancel this deferred:",d d.errback("error") def callback(res): print 'callback got:', res def errback(err): print 'errback got:', err d = defer.Deferred(canceller) d.addCallbacks(callback,errback) d.callback("ok") d.cancel()
因为在cancel时,deferred已被完全激活(返回值不是deferred),则cancel不会起效果,因为if not self.called和elif isinstance(self.result, Deferred)都不满足条件。
所以输出为:
callback got: ok
如果代码是:
from twisted.internet import defer def canceller(d): print "I need to cancel this deferred:",d d.errback("error") def callback(res): print 'callback got:', res def errback(err): print 'errback got:', err d = defer.Deferred(canceller) d.addCallbacks(callback,errback) d.cancel() d.callback("ok")
上面的代码是,我自己在canceller函数中,激活了一个错误回调,这样cancel源码中的self.errback(failure.Failure(CancelledError())) 就不会激活了,因为self.called是True了。
输出结果:
I need to cancel this deferred: <Deferred at 0x23027e8>
errback got: [Failure instance: Traceback (failure with no frames): <class 'twisted.python.failure.DefaultException'>: error
]
Traceback (most recent call last):
File "t.py", line 17, in <module>
d.callback("ok")
File "/usr/lib/python2.7/dist-packages/twisted/internet/defer.py", line 362, in callback
self._startRunCallbacks(result)
File "/usr/lib/python2.7/dist-packages/twisted/internet/defer.py", line 451, in _startRunCallbacks
raise AlreadyCalledError
twisted.internet.defer.AlreadyCalledError
当我不指定canceller参数时,代码如下:
from twisted.internet import defer def canceller(d): print "I need to cancel this deferred:",d d.errback("error") def callback(res): print 'callback got:', res def errback(err): print 'errback got:', err d = defer.Deferred() d.addCallbacks(callback,errback) d.cancel() d.callback("ok")
输出结果:
errback got: [Failure instance: Traceback (failure with no frames): <class 'twisted.internet.defer.CancelledError'>:
]
可见,cancel后面的回调被取消了.