gpt4 book ai didi

python - 释放对延迟 : what's the point 的引用

转载 作者:太空宇宙 更新时间:2023-11-04 05:56:28 25 4
gpt4 key购买 nike

Twisted tutorial 中提到了这种模式作为避免触发相同延迟两次的标准方法:

class A(ClientFactory):
...
def finished(self, result):
if self.deferred is not None:
d, self.deferred = self.deferred, None
d.callback(result)

但据我了解,Deferred 不会让您(即,如果您这样做则引发异常)调用同一个实例两次。那么,为什么要通过在各处重复此代码来重新创建该安全机制?

最佳答案

如您所说,第二次调用 Deferred.callback 将引发 AlreadyCalledError。不过,编写不触发此异常的代码是惯用的。我编写或阅读的大多数使用延迟的代码都试图保留 AlreadyCalledError 来指示编程错误,而不是可以安全忽略的正常运行时条件。

所以:

def finished(self, result):
try:
self.deferred.callback(result)
except AlreadyCalledError:
pass

不是首选拼写。我认为这是因为可能还有其他原因 AlreadyCalledError 被引发,而不仅仅是因为 finished 被多次调用,并且这种错误处理会掩盖这些情况,可能隐藏错误。

丢弃 Deferred 实例的第二个原因是为了帮助记录意外的异常。当一个 Deferred 被垃圾收集并且它有一个未处理的 Failure 结果时,这个 Failure 会被记录下来。这通常表示编程错误。不过,只要有任何对 Deferred 的引用,就不能对其进行垃圾回收,因此丢弃工厂中的引用至少可以确保工厂不会保留 Deferred 还活着(尽管使用 Deferred 的应用程序代码仍然可以)。

另一种方法是这样写:

def finished(self, result):
if self.deferred is not None:
self.deferred.callback(result)
self.deferred = None

这仍然会丢弃 Deferred 但没有元组解包。但是,这里有一个问题。

考虑一个更完整的 A 版本:

class A(ClientFactory):
def waitUntilFinished(self):
self.deferred = Deferred()
return self.deferred

def finished(self, result):
if self.deferred is not None:
d, self.deferred = self.deferred, None
d.callback(result)

如您所见,在 finished 发生一次之前调用 A.waitUntilFinished 两次是不安全的。也就是说,如果你写:

a = A()
x = a.waitUntilFinished()
y = a.waitUntilFinished()

那么您可以非常确定 x 永远不会收到结果。这可能令人难过,但您可以合理地将其记录为 API 的限制。

现在,考虑一下这种略有不同的使用模式:

a = A()
x = a.waitUntilFinished()

def doSomething(result):
return a.waitUntilFinished()
x.addCallback(doSomething)

此代码不再调用 waitUntilFinished 两次,甚至在 finished 被调用一次之前。它会等到 finished 被调用,然后再调用 waitUntilFinished 第二次。如果您将 API 记录为在引发 Deferred 触发之前只能安全调用一次,那么有人可能会认为这种用法是合理的。

使用更简单的实现:

def finished(self, result):
if self.deferred is not None:
self.deferred.callback(result)
self.deferred = None

有问题。 doSomething 作为 self.deferred.callback(result) 的结果被调用。更具体地说,doSomethingself.deferred.callback 返回之前被调用(换句话说,doSomething 被该语句同步调用)。 doSomething 调用 waitUntilFinished 创建一个新的 Deferred 并将其分配给工厂的 deferred 属性。然后 self.deferred.callback(result) 完成并且 self.deferred = None 运行 - 新的Deferred` 被丢弃,永远不会被调用。

通过在 调用其回调链之前将 self.deferred 设置为 None,可以避免这种情况。

关于python - 释放对延迟 : what's the point 的引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27498889/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com