两个或多个协程可以等待 Twisted 中的同一个 Deferred 吗?

Can two or more coroutines await for the same Deferred in Twisted?

我正在尝试使用 deferred 向可能正在等待它的多个协程发出任务结束信号。我想要 threading.Event 中事件的相同行为。协程等待,但只有一个协程得到延迟触发的结果。代码示例:

from twisted.internet import defer, task, reactor

async def test(d):
    print("Awaiting")
    print(f"Await finished: {await d}")

d = defer.Deferred()
defer.ensureDeferred(test(d))
defer.ensureDeferred(test(d))
task.deferLater(reactor, 1, d.callback, 'Deferred Fired')

reactor.run()

输出:

Awaiting
Awaiting
Await finished: Deferred Fired
Await finished: None

我期待:

Awaiting
Awaiting
Await finished: Deferred Fired
Await finished: Deferred Fired

但是当一个协程等待两次或更多次时它工作正常:

async def test(d):
    print("Awaiting")
    print(f"Await finished: {await d}")
    print(f"Await finished: {await d}")

d = defer.Deferred()
defer.ensureDeferred(test(d))
task.deferLater(reactor, 1, d.callback, 'Deferred Fired')

您正在尝试使用 deferreds 作为一种同步方法,但这并不是它真正的预期目的,至少不是它自己的目的。我假设您想像使用 Event.wait() 一样使用 Deferred?这是我经常看到的范例:

from dataclasses import dataclass, field
from typing import List

from twisted.internet import defer, reactor

@dataclass
class Thing:

    deferred_list: List[defer.Deferred] = field(default_factory=list)

    def notifyFinished(self) -> defer.Deferred:
        deferred = defer.Deferred()
        self.deferred_list.append(deferred)
        return deferred

    def finish(self):
        for index, deferred in enumerate(self.deferred_list):
            deferred.callback(index + 1)
        self.deferred_list = []

async def doSomethingElse(d):
    print("[!] awaiting...")
    print(f"[x] done waiting: {await d}")

def main():
    thing = Thing()
    for _ in range(5):
        d = thing.notifyFinished()
        defer.ensureDeferred(doSomethingElse(d))
    reactor.callLater(5, thing.finish)
    reactor.run()

main()

这里我们有一个函数 returns a deferred/future(即 notifyFinished),跟踪那些被推迟的,一旦一个工作完成,调用一个函数来发出信号作业结束(即 finish)。 Deferred 旨在仅触发一次(Future 也可能,但不要引用我的话),因此使用此方法可确保返回单个 Deferred 对象并同时触发时间。