Google app engine 如何防止ndb批处理put_async()调用并使其立即发出RPC?

Google app engine 如何防止ndb批处理put_async()调用并使其立即发出RPC?,google-app-engine,app-engine-ndb,Google App Engine,App Engine Ndb,我有一个请求处理程序,它更新一个实体,将其保存到数据存储中,然后在返回之前需要执行一些额外的工作(如对后台任务进行排队和json序列化某些结果)。我想并行化这段代码,以便在保存实体时完成额外的工作 下面是我的处理程序代码的总结: 类FooHandler(webapp2.RequestHandler): @顶级 def post(自我): foo=yield foo.get\u by\u id\u async(some\u id) #和foo一起工作 #不要屈服,因为我想执行下面的代码 #将foo

我有一个请求处理程序,它更新一个实体,将其保存到数据存储中,然后在返回之前需要执行一些额外的工作(如对后台任务进行排队和json序列化某些结果)。我想并行化这段代码,以便在保存实体时完成额外的工作

下面是我的处理程序代码的总结:

类FooHandler(webapp2.RequestHandler):
@顶级
def post(自我):
foo=yield foo.get\u by\u id\u async(some\u id)
#和foo一起工作
#不要屈服,因为我想执行下面的代码
#将foo保存到数据存储时。
#我处于顶层,所以只要
#此异步请求未完成。
foo.put_async()
taskqueue.add(…)
json_result=生成_result()
self.response.headers[“Content Type”]=“application/json;charset=UTF-8”
self.response.write(json_结果)
但是,Appstats显示,
datastore.Put
RPC是在
taskqueue.Add
之后连续执行的:

ndb.context.py
中稍微挖掘一下,就会发现
put\u async()
调用最终被添加到
AutoBatcher
中,而不是立即发出RPC

因此,我假设
\u put\u批处理程序
顶层
等待所有异步调用完成时被刷新

我知道批处理put在某些场景中有真正的好处,但在我这里的例子中,我真的希望立即发送put RPC,以便在保存实体时执行其他工作

如果我做了
yield foo.put_async()
,那么我会在Appstats中得到相同的瀑布,但是
datastore.put
会在其余部分之前完成:

这是意料之中的,因为
yield
使我的处理程序等待
put\u async()
调用完成,然后再执行其余的代码

我还尝试在
foo.put\u async()
之后添加对
ndb.get\u context().flush()
的调用,但根据Appstats,数据存储区.put和
任务队列.BulkAdd
调用仍然没有并行进行


所以我的问题是:如何强制调用
put_async()
绕过自动批处理程序并立即发出RPC?

试试这个,我不能100%肯定它会有帮助:

foo = yield Foo.get_by_id_async(some_id)
future = foo.put_async()
future.done()
ndb请求被放入AutoWatcher,当您需要结果时,批处理被发送到RPC。由于您不需要foo.put_async()的结果,因此在您进行另一个ndb调用(您不需要)或@ndb.toplevel结束之前,它不会被发送

调用future.done()不会阻塞,但我猜它可能会触发请求

另一种尝试强制操作的方法是:

ndb.get_context().flush()

没有支持的方法可以做到这一点。也许应该有。你能试试这个吗

loop - ndb.eventloop.get_event_loop()
while loop.run_idle():
    pass
您可能需要查看ndb/eventloop.py的源代码,看看还有什么可以尝试的——基本上,除了等待RPC之外,您希望尝试run0()的大部分功能。特别是,您可能必须这样做:

while loop.current:
    loop.run0()
while loop.run_idle():
    pass

(这仍然不受支持,因为您可能还需要处理其他情况,但这些情况在您的示例中似乎没有发生。)

是在生产环境中还是本地环境中?谢谢,但它没有任何作用
Future.done()
只返回self.\u done没有任何处理,我已经尝试了
Context.flush()
。我通过调用
ndb.get\u Context().flush()
,然后在调用
foo.put\u async()
之后,调用了您建议的两个循环,使其正常工作。我相信应该有一种官方支持的方法来做到这一点,因为我认为我的使用场景并不少见(保存一个实体,然后在保存实体时结束剩余的处理程序工作)。我为它提交了一个功能请求:我认为真正需要的是taskqueue.add_async,以便将任务队列rpc放入eventloop中的idle/rpc循环。对你有效的代码是什么?flush()是一个tasklet,因此您必须生成它,这可能会导致比您希望的更多的延迟。无论如何,我同意这将是一个有用的特性。如果将其归档到NDB跟踪器中,可能会引起更多的注意?如果put也包括memcache集,则run_idle将仅设置memcache rpc,而不是数据存储rpc。数据存储rpc将在taskqueue添加后执行。@GuidovanRossum,我已经编辑了您的答案,其中包含了对我有用的详细信息,但由于某些原因,该编辑未获得批准。。。正如我在前面的评论中所说:调用
flush()
,然后执行您建议的两个循环。