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

Python 这是ndb异步urlfetch tasklet的一个很好的用例吗?,python,google-app-engine,python-2.7,urlfetch,Python,Google App Engine,Python 2.7,Urlfetch,我想转到ndb,一直想知道是否使用asyncurlfetch。我不确定我是否完全理解它是如何工作的,因为文档有点糟糕,但是对于这个特定的用例来说,它似乎很有希望 目前我像这样使用asyncurlfetch。它与实际的线程化或并行代码相去甚远,但与仅顺序请求相比,它仍然显著提高了性能 def http_get(url): rpc = urlfetch.create_rpc(deadline=3) urlfetch.make_fetch_call(rpc,url) retur

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

目前我像这样使用async
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
def http_get(url):
rpc=urlfetch.create_rpc(截止日期=3)
urlfetch.make_fetch_调用(rpc,url)
返回rpc
rpcs=[]
URL=[…]#数百个URL
rpcs<10时:
append(http_get(url.pop()))
而RPC:
rpc=rpcs.pop(0)
result=rpc.get_result()
如果result.status_code==200:
#将另一项附加到RPC
#过程结果
其他:
#将同一项重新附加到RPC
请注意,此代码已简化。实际的代码捕获异常,进行一些额外的检查,并且只尝试重新附加同一项几次。这对这个案子没有区别


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

实际上是的,在这里使用异步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值的列表,指示获取成功


我不确定这将在多大程度上提高整体生产力(这取决于谷歌方面),但它应该这样做

如果您问在您的用例中使用ndb是否有性能,那么解决方案不是度量性能吗?不清楚你在问什么,我有个问题。在您的示例中,当我有100个URL并与列表理解一样使用urlfetch时,服务器不会立即启动100个连接吗?我是否可以将此限制为一次连接不超过10个(如我发布的代码中所示),以避免同时请求过多而使另一台服务器紧张?我可能只需要将
url
拆分为10个列表,但在处理结果后,我无法将列表重新填充为10个项目。看起来我可以把我的代码和自定义的Tasklet结合起来使用,但这可能没有任何好处。据我所知,如果你触发100个连接,你将无法控制它们。它们由异步控制。经纪人。所以,如果您需要将bulk限制为10,那么您需要获取前10个URL,将它们提交给处理,等待结果,然后获取下一个10,以此类推……实际上,您的代码实际上是在进行异步调用,所以在这里使用ndb的主要原因是——使保存数据也异步,但HTTP调用比存储数据长得多(我认为谷歌的云存储足够快),所以我认为您不会从中受益太多。我最好尝试调整批处理大小,看看它有什么帮助。嗯,您是对的。我希望这是一种更优雅的使用异步urlfetch的方法,但如果不涉及
ndb
操作,则使用Tasklet似乎毫无意义。您实际上已经在使用异步urlfetch,因此无需添加任何内容。