deferredのcancelソースコードからcancelの動作を分析する

5474 ワード

まずは見てみましょう、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:#deferdがアクティブになっていない場合は、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は1回しかアクティブにならないため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:
errback got: [Failure instance: Traceback (failure with no frames):
]
Traceback (most recent call last):
  File "t.py", line 18, in
    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()

キャンセル時にdeferredが完全にアクティブになっているため(戻り値がdeferredではない)、if not selfのためcancelは効果がない.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:
errback got: [Failure instance: Traceback (failure with no frames): : error
]
Traceback (most recent call last):
  File "t.py", line 17, in
    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):
]
cancelの後のコールバックがキャンセルされたことがわかります.