如何使扭曲的延迟操作列表真正异步

问题描述

我是使用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的调用方中很难解决。