【问题标题】:Python DeferredList callback reporting success when deferreds raise errorPython DeferredList 回调在延迟引发错误时报告成功
【发布时间】:2014-04-28 21:32:26
【问题描述】:

我有以下简单的脚本:

#!/usr/bin/env python
from twisted.internet import defer             
from twisted.web.client import getPage, reactor

def success(results):
  print 'success'              

def error(results):
  print 'error'         

def finished(results):
  print 'finished', results

tasks = []

d = getPage('thiswontwork').addCallback(success).addErrback(error)
tasks.append(d)

dl = defer.DeferredList(tasks)
dl.addCallback(finished)

reactor.run()

产生以下输出:

error
finished [(True, None)]

我希望这个错误任务返回一个错误,因为 getPages 任务失败并调用它的错误回调。任何人都可以解释这种行为吗?

【问题讨论】:

    标签: python asynchronous twisted


    【解决方案1】:

    让我在您选择的答案之外添加一个想法:

    在您的问题中,您打印了调用 deferred(list) 回调(finished) 的参数,并且您注意到您希望它是false(因为之前发生的错误)

    这种期望表明您对延期的想法会让您感到困惑later

    让我看看我能不能把它拆开……

    (这东西有很多细节和微妙之处,我会尽力而为)

    延迟是:

    1. 函数回调队列
    2. 其中,对于队列中的每个“步骤”,都存储了 callbackerrback 函数回调
      • addCallbacks(注意它的复数形式)允许您同时添加回调和 errback
      • addCallback 添加回调(并设置 errback 以跳到队列中的下一个条目)
      • addErrback 添加 errback (并设置回调跳到队列中的下一个条目)
      • addBoth 添加一个函数作为 errback 和回调(...这意味着它需要弄清楚为什么它是通过 arg 调用它的原因

    取自krondo's part 7:(...Twisted 文档也有good drawing

    如果一个函数以callback 的形式添加到deferred,并且deferred 在其“触发”中达到了该步骤之前的步骤成功返回的点,则deferred 将前一个成功函数的返回值传递给callback中定义的函数。

    如果将函数作为errback 添加到延迟对象,并且延迟对象在其“触发”中已到达上一步返回Failure 对象的点(或引发异常,该异常会扭曲转换为@ 987654342@ 对象),然后将使用该 Failure 对象调用 errback注意!如果 errback 没有返回 Failure,则 deferred 将返回调用 callback 链,而不是 errback!

    取材自Krondo's part 9

    虽然这一切看起来有点让人费解,但它可以让您实现诸如中延迟错误恢复之类的东西,这真的很有帮助(在协议设计中并不少见)

    I.E:(取自Krondo's part 9):

    总而言之,您认为“我希望此错误任务返回 false”的错误是 finished 不被任何类型的错误任务调用,它由延迟调用,并且最重要的是它只在成功时调用(因为它只作为callback而不是errback加载到延迟中)

    如果您已将 finished 函数加载为 errbackcallback(可能通过 addBoth),并且您已按照答案建议通过返回Failure 对象,你的 finished 函数在技术上仍然不会被传递 False!它会收到一个Failure 对象。

    ...就像我说的,这东西有很多微妙之处...

    如果您发现其中有任何帮助(...或者即使您没有 - 我不是一个优秀的作家),您真的应该深入了解 Krondo's twisted introduction。我想您在阅读完该指南后会发现其中的很多内容。

    【讨论】:

    • 谢谢 Mike,我非常感谢这个深入的答案,现在我肯定以错误的方式考虑延期了。
    【解决方案2】:

    如果您没有从errback 返回错误/异常,则认为该错误已得到处理。尝试更改您的 error() 函数:

    def error(results):
        print 'error'
        return results
    

    这样会返回错误(results),然后DeferredList 会看到错误并调用它的errback

    【讨论】:

    • 这是有道理的,我假设如果它通过错误回调它就会知道发生了错误。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2012-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多