从deferred的cancel源代码中分析cancel的工作方式

首先来看看,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后面的回调被取消了.


你可能感兴趣的:(python,twisted)