twisted: 无用的“已调用”错误

7 投票
2 回答
3180 浏览
提问于 2025-04-16 04:39

我这个奇怪的Python程序总是时不时地出现这个信息:

Unhandled error in Deferred:

Traceback (most recent call last):
  File "c:\python25\lib\site-packages\twisted\internet\defer.py", line 757, in gotResult
    _inlineCallbacks(r, g, deferred)
  File "c:\python25\lib\site-packages\twisted\internet\defer.py", line 747, in _inlineCallbacks
    deferred.errback()
  File "c:\python25\lib\site-packages\twisted\internet\defer.py", line 269, in errback
    self._startRunCallbacks(fail)
  File "c:\python25\lib\site-packages\twisted\internet\defer.py", line 312, in _startRunCallbacks
    self._runCallbacks()
--- <exception caught here> ---
  File "c:\python25\lib\site-packages\twisted\internet\defer.py", line 328, in _runCallbacks
    self.result = callback(self.result, *args, **kw)
  File "c:\python25\lib\site-packages\twisted\internet\defer.py", line 243, in callback
    self._startRunCallbacks(result)
  File "c:\python25\lib\site-packages\twisted\internet\defer.py", line 298, in _startRunCallbacks
    raise AlreadyCalledError
twisted.internet.defer.AlreadyCalledError:

这个信息对我来说没什么帮助,因为它没有指向我的源代码... 我还在用defer.inlineCallbacks。你知道可能出了什么问题吗?

2 个回答

2

我想你代码中的某个地方,可能是你在明确地调用了一个叫做“deferred”的回调。而且这个回调被调用了多次。其实,deferred的回调只能被触发一次,这个回调的作用是表示一个长时间等待的任务已经完成,可能是出错了,也可能是成功了。如果你试图多次触发这个deferred,Twisted会有机制来抛出上述的错误。

看看下面这段代码:

from twisted.internet.defer import Deferred
def func(x): print x
d = Deferred()
d.addCallbacks(func, func)
d.callback('First fire')
d.callback('Second fire')

这段代码会导致以下错误:

    raise AlreadyCalledError
twisted.internet.defer.AlreadyCalledError

请检查一下你的代码,看看是否有多次触发的情况。这可能就是问题所在。

7

如果你没有其他线索来判断问题出在哪里(比如你的单元测试指出了具体导致问题的情况,或者pyfunc的回答没有让你明白为什么会这样),那么可以启用延迟调试,这样可以获取关于延迟对象(Deferred)第一个(也是唯一允许的)结果是在哪里被指定的信息:

from twisted.internet import defer
defer.setDebugging(True)

或者

twistd --debug [...]

或者

trial --debug [...]

这样你会得到额外的错误报告和堆栈追踪信息,类似于你遇到的那个错误。额外的堆栈追踪会告诉你这个延迟对象是在哪里创建的,以及它第一次被调用(调用了.callback()或.errback())的地方。

因为你在使用inlineCallbacks,所以你不会得到一个清晰的堆栈追踪来告诉你实际错误发生的位置,但关于延迟对象第一次被触发的信息可能会给你一些线索,帮助你找到后续激活的来源。

不幸的是,使用inlineCallbacks目前带来的一些模糊性是不可避免的。这可能是可以解决的,但需要有人来承担这个任务。

撰写回答