问题描述
我是使用Twisted库的新手,我想列出一个异步操作列表。以以下伪代码为例:
@defer.inlineCallbacks
def getDataAsync(host):
data = yield AsyncHttpAPI(host) # some asyc api which returns deferred
return data
@defer.inlineCallbacks
def funcPrintData():
hosts = []; # some list of hosts,say 1000 in number
for host in hosts:
data = yield getDataAsync(host)
# why doesn't the following line get printed as soon as first result is available
# it waits for all getDataAsync to be queued before calling the callback and so print data
print(data)
如果问题不清楚,请发表评论。有更好的方法吗?我应该改用DeferredList吗?
解决方法
该行:
data = yield getDataAsync(host)
表示“在getDataAsync(host)
操作完成之前停止运行此函数。如果该函数停止运行,则for
循环无法进行任何后续迭代,因此,这些操作甚至无法开始在第一个getDataAsync(host)
完成之后。如果要同时运行所有内容,则需要不停止运行该功能,直到所有操作都开始为止。例如:
ops = []
for host in hosts:
ops.append(getDataAsync(host))
运行之后,无论是否完成任何操作,所有操作都将开始。
对ops
的处理方式取决于是否要按与hosts
相同的顺序获取结果,还是要在准备就绪后立即全部获取,还是要一次获取全部结果?操作成功的时间。
DeferredList
用于将它们全部准备好后,以与输入列表(ops
)相同的顺序立即将它们全部获取:
datas = yield DeferredList(ops)
如果要在每个结果可用时对其进行处理,则使用addCallback
会更容易:
ops = []
for host in hosts:
ops.append(getDataAsync(host).addCallback(print))
这仍然不是yield
,因此整个操作组开始了。但是,对每个操作的回调在该操作产生结果后立即运行。在Deferred
中,您仍然剩下ops
个实例的列表,如果您想要或将整体错误处理附加到其中(至少其中一个,则可以使用它们来等待所有结果完成)是个好主意,否则您将有一些悬而未决的操作,在funcPrintDat
的调用方中很难解决。