我想转移到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
操作。
答案 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值列表,指示获取成功。
我不确定,这将提高整体生产力(这取决于谷歌方面),但它应该。