无法取消 Twisted Deferred 链(AlreadyCalledError)
Unable to cancel Twisted Deferred chain (AlreadyCalledError)
每当某些链式延迟 (child) 引发错误时,我都会尝试取消 Deferred
链(主)。
但是我得到了 AlreadyCalledError
并且连锁店继续其工作。
代码如下:
from twisted.internet import defer
def asyncText(s, okCallback, errCallback):
deferred = defer.Deferred()
deferred.addCallbacks(okCallback, errCallback)
if s.find('STOP')>=0:
deferred.errback(ValueError('You are trying to print the unprintable :('))
else:
deferred.callback(s)
return deferred
def asyncChain():
texts = ['Hello Whosebug,',
'this is an example of Twisted.chainDeferred()',
'which is raising an AlreadyCalledError',
'when I try to cancel() it.',
'STOP => I will raise error and should stop the main deferred',
'Best regards'
]
mainDeferred= defer.Deferred()
for text in texts:
def onSuccess(res):
print('>> {}'.format(res))
def onError(err):
print('Error!! {}'.format(err))
mainDeferred.cancel()
d = asyncText(text, onSuccess, onError)
mainDeferred.chainDeferred(d)
这是输出:
>>> asyncChain()
- Hello Whosebug,
- this is an example of Twisted.chainDeferred()
- which is raising an AlreadyCalledError
- when I try to cancel() it.
Error!! [Failure instance: Traceback (failure with no frames): <class 'ValueError'>: You are trying to print the unprintable :(
]
- Best regards
Unhandled error in Deferred:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File ".../test.py", line 1, in asyncChain
mainDeferred.chainDeferred(d)
File ".../.venvs/p3/lib/python3.6/site-packages/twisted/internet/defer.py", line 435, in chainDeferred
return self.addCallbacks(d.callback, d.errback)
File ".../.venvs/p3/lib/python3.6/site-packages/twisted/internet/defer.py", line 311, in addCallbacks
self._runCallbacks()
--- <exception caught here> ---
File ".../.venvs/p3/lib/python3.6/site-packages/twisted/internet/defer.py", line 654, in _runCallbacks
current.result = callback(current.result, *args, **kw)
File ".../.venvs/p3/lib/python3.6/site-packages/twisted/internet/defer.py", line 501, in errback
self._startRunCallbacks(fail)
File ".../.venvs/p3/lib/python3.6/site-packages/twisted/internet/defer.py", line 561, in _startRunCallbacks
raise AlreadyCalledError
twisted.internet.defer.AlreadyCalledError:
我也试过使用 canceller
,像这样:
def asyncOnCancel(d):
print('------ cancel() called ------')
d.errback(ValueError('chain seems to be cancelled!'))
def asyncChainOnError(err):
print('------ ERROR ON Chain {} ------'.format(err))
...
mainDeferred= defer.Deferred(canceller= asyncOnCancel)
mainDeferred.addErrback(asyncChainOnError)
...
但结果是一样的
我也试过延迟 child .callback(s)
次调用,或者在 .chainDeferred()
之后调用它们。但我总是得到同样的行为。
- 真的有可能 取消 链式
Deferred
(并且被链式 child 延迟也被取消)?
- 为什么我收到这个
AlreadyCalledError
?
我正在使用 python 3.6.6 和 Twisted 18.9.0。
谢谢!
******* 编辑 *******
在 回答后,注意到 .chainDeferred()
不是我需要的,我将在这里更清楚地说明我想要什么(以及我最终是如何做到的)。
我想要的更简单:运行 几个 Deferred,以 "synchronous" 的方式(他们必须等待前一个完成),尽管他们不需要分享他们的成果。一个失败,其余的不执行。
原来用 @defer.inlineCallbacks
和 yield
很容易做到。举个例子:
def asyncText(s):
deferred = defer.Deferred()
if s.find('STOP') >= 0:
deferred.callback(True)
else:
deferred.callback(False)
return deferred
@defer.inlineCallbacks
def asyncChain():
texts = ['Hello Whosebug,',
'this is a simpler way to explain the question.',
'I need no chainDeferred(). I need no .cancel().',
'I just need inlineCallbacks decorator.',
'STOP',
'Yeah I will not be printed'
]
for text in texts:
stopHere = yield asyncText(text)
if stopHere:
break
print('- {}'.format(text))
deferred= asyncChain()
>>> asyncChain()
- Hello Whosebug,
- this is a simpler way to explain the question.
- I need no chainDeferred(). I need no .cancel().
- I just need inlineCallbacks decorator.
不清楚您实际想要做什么,但我认为您的链条与您的预期相反:
d = asyncText(text, onSuccess, onError)
mainDeferred.chainDeferred(d)
d
已在 asyncText
returns 时触发。但是 mainDeferred.chainDeferred(d)
意味着 "when mainDeferred fires, pass its result to d"。因为 d
已经开火了,所以这是无效的。 Deferred 只能触发一次。
也许您的意思是 d.chainDeferred(mainDeferred)
。然后"when d fires, pass its result to mainDeferred".
但是,仍然存在一个问题,因为如果您将 d
链接到 mainDeferred
,那么 取消 [=17 就没有意义了=] 在 d
的回调中。结果将从 d
传播到 mainDeferred
,因为它们是链接在一起的。取消没有必要也没有用。
每当某些链式延迟 (child) 引发错误时,我都会尝试取消 Deferred
链(主)。
但是我得到了 AlreadyCalledError
并且连锁店继续其工作。
代码如下:
from twisted.internet import defer
def asyncText(s, okCallback, errCallback):
deferred = defer.Deferred()
deferred.addCallbacks(okCallback, errCallback)
if s.find('STOP')>=0:
deferred.errback(ValueError('You are trying to print the unprintable :('))
else:
deferred.callback(s)
return deferred
def asyncChain():
texts = ['Hello Whosebug,',
'this is an example of Twisted.chainDeferred()',
'which is raising an AlreadyCalledError',
'when I try to cancel() it.',
'STOP => I will raise error and should stop the main deferred',
'Best regards'
]
mainDeferred= defer.Deferred()
for text in texts:
def onSuccess(res):
print('>> {}'.format(res))
def onError(err):
print('Error!! {}'.format(err))
mainDeferred.cancel()
d = asyncText(text, onSuccess, onError)
mainDeferred.chainDeferred(d)
这是输出:
>>> asyncChain()
- Hello Whosebug,
- this is an example of Twisted.chainDeferred()
- which is raising an AlreadyCalledError
- when I try to cancel() it.
Error!! [Failure instance: Traceback (failure with no frames): <class 'ValueError'>: You are trying to print the unprintable :(
]
- Best regards
Unhandled error in Deferred:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File ".../test.py", line 1, in asyncChain
mainDeferred.chainDeferred(d)
File ".../.venvs/p3/lib/python3.6/site-packages/twisted/internet/defer.py", line 435, in chainDeferred
return self.addCallbacks(d.callback, d.errback)
File ".../.venvs/p3/lib/python3.6/site-packages/twisted/internet/defer.py", line 311, in addCallbacks
self._runCallbacks()
--- <exception caught here> ---
File ".../.venvs/p3/lib/python3.6/site-packages/twisted/internet/defer.py", line 654, in _runCallbacks
current.result = callback(current.result, *args, **kw)
File ".../.venvs/p3/lib/python3.6/site-packages/twisted/internet/defer.py", line 501, in errback
self._startRunCallbacks(fail)
File ".../.venvs/p3/lib/python3.6/site-packages/twisted/internet/defer.py", line 561, in _startRunCallbacks
raise AlreadyCalledError
twisted.internet.defer.AlreadyCalledError:
我也试过使用 canceller
,像这样:
def asyncOnCancel(d):
print('------ cancel() called ------')
d.errback(ValueError('chain seems to be cancelled!'))
def asyncChainOnError(err):
print('------ ERROR ON Chain {} ------'.format(err))
...
mainDeferred= defer.Deferred(canceller= asyncOnCancel)
mainDeferred.addErrback(asyncChainOnError)
...
但结果是一样的
我也试过延迟 child .callback(s)
次调用,或者在 .chainDeferred()
之后调用它们。但我总是得到同样的行为。
- 真的有可能 取消 链式
Deferred
(并且被链式 child 延迟也被取消)? - 为什么我收到这个
AlreadyCalledError
?
我正在使用 python 3.6.6 和 Twisted 18.9.0。
谢谢!
******* 编辑 *******
在 .chainDeferred()
不是我需要的,我将在这里更清楚地说明我想要什么(以及我最终是如何做到的)。
我想要的更简单:运行 几个 Deferred,以 "synchronous" 的方式(他们必须等待前一个完成),尽管他们不需要分享他们的成果。一个失败,其余的不执行。
原来用 @defer.inlineCallbacks
和 yield
很容易做到。举个例子:
def asyncText(s):
deferred = defer.Deferred()
if s.find('STOP') >= 0:
deferred.callback(True)
else:
deferred.callback(False)
return deferred
@defer.inlineCallbacks
def asyncChain():
texts = ['Hello Whosebug,',
'this is a simpler way to explain the question.',
'I need no chainDeferred(). I need no .cancel().',
'I just need inlineCallbacks decorator.',
'STOP',
'Yeah I will not be printed'
]
for text in texts:
stopHere = yield asyncText(text)
if stopHere:
break
print('- {}'.format(text))
deferred= asyncChain()
>>> asyncChain()
- Hello Whosebug,
- this is a simpler way to explain the question.
- I need no chainDeferred(). I need no .cancel().
- I just need inlineCallbacks decorator.
不清楚您实际想要做什么,但我认为您的链条与您的预期相反:
d = asyncText(text, onSuccess, onError)
mainDeferred.chainDeferred(d)
d
已在 asyncText
returns 时触发。但是 mainDeferred.chainDeferred(d)
意味着 "when mainDeferred fires, pass its result to d"。因为 d
已经开火了,所以这是无效的。 Deferred 只能触发一次。
也许您的意思是 d.chainDeferred(mainDeferred)
。然后"when d fires, pass its result to mainDeferred".
但是,仍然存在一个问题,因为如果您将 d
链接到 mainDeferred
,那么 取消 [=17 就没有意义了=] 在 d
的回调中。结果将从 d
传播到 mainDeferred
,因为它们是链接在一起的。取消没有必要也没有用。