1

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

目前我像这样使用异步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操作。

4

1 回答 1

0

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

简单的例子:

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 值的列表,表明获取成功。

我不确定这会在多大程度上提高整体生产力(这取决于谷歌方面),但应该如此。

于 2012-11-27T09:53:04.717 回答