为什么使用Deferred.result来获取Twisted Deferred对象的结果是错误的?

2024-06-01 04:16:26 发布

您现在位置:Python中文网/ 问答频道 /正文

从我所读到的内容来看,绝不应该使用扭曲的result对象的Deferred属性来访问延迟对象的值。我怀疑原因是

  1. 访问时可能没有可用的结果(请参阅) AttributeError
  2. 在访问时,结果可能不是最终的(即不是全部) 回调已运行)

是否曾经有过这样一种情况,即获得递延所得税结果的价值是适当的?有没有更好的方法来访问结果,将其分配给一个变量,或者在以后使用它,而不向延迟对象添加额外的回调?你知道吗


Tags: 对象方法内容属性情况请参阅原因result
2条回答

你的怀疑基本上是正确的。你知道吗

No result may not be available at the time of access (raises AttributeError)

Deferred的思想是,有些工作正在发生,在某个固定的时间内不会完成。当它完成的时候它就会完成。幸运的是,当它完成时,Deferred可以告诉您结果—这就是回调的目的。这意味着,如果没有使用回调,就无法知道工作何时完成。您可能太早检查并得到一个AttributeError(或者其他类型的失败,下面将对此进行详细介绍)。你可能检查得太晚,浪费了一些时间。你可以通过反复检查和处理错误来“修复”过早的情况。这称为“轮询”。Twisted的很大一部分是为了消除执行轮询的需要,因为轮询通常是不受欢迎的(代价很高)。解决“太迟”的唯一方法是更频繁地检查——这会使“太早”的情况更糟。你知道吗

The result may not be final at the time of access (i.e. not all callbacks have run)

Deferred提供的一个特性是,它允许在事件驱动编程中进行合成。您可以有一个执行某些任务并返回Deferred的单元。单元B可以执行一些任务,依赖于单元A并返回一些其他的Deferred。这样的构图可以是这样的:

d = Deferred()

d_a = unit_a()
def a_finished(result):
    d_b = unit_b(result)
    d_b.addCallback(d_final.callback)
d_a.addCallback(a_finished)

在这个例子的执行过程中,d.result采用什么值?首先它是一个AttributeError,然后它是用unit_bDeferred调用的任何值。在这种情况下,您不会暴露出不完整或中间的结果,也不会有任何问题。然而,这种组合是笨拙的、冗长的和容易失败的(例如,它遗漏了错误传播和取消特性)。你知道吗

编写Deferredapi的简单、惯用、受鼓励的方法是:

d = unit_a()
d.addCallback(unit_b)

更容易写,更容易读,你得到的功能,如铁路式错误传播。你知道吗

在这种情况下,d.result有什么价值观呢?首先是一个AttributeError。然后,在unit_a完成之后,d.resultunit_b返回的Deferred。因此,如果你在这里查找,不仅没有最终结果,甚至没有实际值,反而有一个Deferred。只有在unit_b完成之后,d才会呈现unit_b的真实结果。你知道吗

还有其他可能的序列。它们产生于其他的Deferred使用模式,这些使用模式不像上面的那样受欢迎,但它们肯定是可能的。例如,您可能有这样一个实现:

d = unit_a()

然后将d暴露给您的代码。在这一点之后,您可能需要执行以下操作:

d.addCallback(unit_b)

现在d.resultAttributeErrorunit_a的结果,再到Deferredunit_b的结果。上面提到的并不是Deferred的优秀用法,但是正如您所看到的,这是完全可能的。在这种情况下,如果您正在轮询d.result,那么您将不得不猜测非Deferred值是unit_a还是unit_b的结果。你知道吗

Is there ever a situation where it is appropriate to access the value of the result of the Deferred?

很难完全排除。当然,在Deferred本身的测试套件中有一些直接访问,这些访问可能是合法的。在其他一些与测试相关的工具中,这样访问result属性可能是合适的,但理想情况下,即使在那里也可以避免,或者测试库(比如Twisted的试用版)可以提供更好的工具来编写这类测试(例如试用版确实提供了successResultOffailureResultOfassertNoResult)。除此之外,我认为您应该非常仔细地研究result属性的任何用法,您可能会发现有一个更好的(更易维护、更不脆弱的)使用回调的解决方案。你知道吗

Is there a better way to access the result to assign it to a variable or use it later without adding additional callbacks to the Deferred?

访问结果的更好方法总是添加一个额外的回调。另一个答案表明,inlineCallbacks是一种使用回调的方法,它看起来不像使用回调,而且是许多人的首选。它可以让你做一个简单的分配到一个本地ret但是实现仍然使用Deferred.addCallback和相关的api。你知道吗

我想这就是你要找的。使用inlinecallbacks,您可以访问结果,而无需编写回调。你知道吗

@inlineCallBacks def thingummy(): thing = yield makeSomeRequestResultingInDeferred() print(thing) # the result! hoorj!

https://twistedmatrix.com/documents/13.2.0/api/twisted.internet.defer.inlineCallbacks.html

相关问题 更多 >