这里有一种可能的方法。
from __future__ import print_function
import attr
from twisted.internet.defer import Deferred
def fireOnN(n, ds):
acc = _Accumulator(n)
for index, d in enumerate(ds):
d.addCallback(acc.one_result, index)
return acc.n_results
@attr.s
class _Accumulator(object):
n = attr.ib()
so_far = attr.ib(default=attr.Factory(dict))
done = attr.ib(default=False)
n_results = attr.ib(default=attr.Factory(Deferred))
def one_result(self, result, index):
if self.done:
return result
self.so_far[index] = result
if len(self.so_far) == self.n:
self.done = True
so_far = self.so_far
self.so_far = None
self.n_results.callback(so_far)
dx = list(Deferred().addCallback(print, i) for i in range(3))
done = fireOnN(2, dx)
done.addCallback(print, "done")
for i, d in enumerate(dx):
d.callback("result {}".format(i))
请注意,此实现不处理错误,可能还有其他缺点(如保留
n_results
参考)。然而,基本思想是合理的:从回调中积累状态,直到达到所需的条件,然后触发另一个延迟状态。
DeferredList
这只会给这个问题带来不必要的复杂性,因为它的无关特性和界面不是为解决这个问题而设计的。