这是ndb异步urlfetch tasklets的一个很好的用例吗?

时间:2012-11-24 15:01:03

标签: python google-app-engine python-2.7 urlfetch

我想转移到ndb,并一直想知道是否使用异步urlfetch tasklets。我不确定我是否完全理解它是如何工作的,因为文档有点差,但对于这个特定的用例似乎很有希望。

目前我像这样使用异步urlfetch。它远非实际的线程或并行代码,但与仅仅是顺序请求相比,它仍然相当显着地提高了性能。

def http_get(url):
    rpc = urlfetch.create_rpc(deadline=3)
    urlfetch.make_fetch_call(rpc,url)
    return rpc

rpcs = []
urls = [...] # hundreds of urls

while rpcs < 10:
    rpcs.append(http_get(urls.pop()))

while rpcs:
    rpc = rpcs.pop(0)
    result = rpc.get_result()
    if result.status_code == 200:
        # append another item to rpcs
        # process result
    else:
        # re-append same item to rpcs

请注意,此代码已简化。实际代码捕获异常,有一些额外的检查,并且只尝试重新添加相同的项目几次。这种情况没有区别。

我应该补充说,处理结果不涉及任何db操作。

1 个答案:

答案 0 :(得分:0)

实际上是的,在这里使用async urlfetch是个好主意。它是如何工作的(粗略解释): - 您的代码到达异步调用点。它会触发长时间的后台任务而不会等待它的结果,但会继续执行。 - 任务在后台运行,当结果准备就绪时 - 它会将结果存储在somwhere中,直到你要求它为止。

简单示例:

def get_fetch_all():
    urls = ["http://www.example.com/", "http://mirror.example.com/"]
    ctx = ndb.get_context()
    futures = [ctx.urlfetch(url) for url in urls]
    results = ndb.Future.wait_all(futures)
    # do something with results here

如果要将结果存储在ndb中并使其更加优化 - 最好为此编写自定义tasklet。

@ndb.tasklet
def get_data_and_store(url):
    ctx = ndb.get_context()
    # until we don't receive result here, this function is "paused", allowing other 
    # parallel tasks to work. when data will be fetched, control will be returned
    result = yield ctx.urlfetch("http://www.google.com/") 
    if result.status_code == 200:
        store = Storage(data=result.content)
        # async job to put data
        yield store.put_async()
        raise ndb.Return(True)
    else:
        raise ndb.Return(False)

您可以在第一个示例中将此tasklet与循环结合使用。您应该获得ther / false值列表,指示获取成功。

我不确定,这将提高整体生产力(这取决于谷歌方面),但它应该。