我有一个请求处理程序,它更新实体,将其保存到数据存储区,然后需要在返回之前执行一些额外的工作(比如排队后台任务和json序列化一些结果)。我想并行化这段代码,以便在保存实体时完成额外的工作。
以下是我的处理程序代码归结为:
class FooHandler(webapp2.RequestHandler):
@ndb.toplevel
def post(self):
foo = yield Foo.get_by_id_async(some_id)
# Do some work with foo
# Don't yield, as I want to perform the code that follows
# while foo is being saved to the datastore.
# I'm in a toplevel, so the handler will not exit as long as
# this async request is not finished.
foo.put_async()
taskqueue.add(...)
json_result = generate_result()
self.response.headers["Content-Type"] = "application/json; charset=UTF-8"
self.response.write(json_result)
但是,Appstats显示在datastore.Put
之后taskqueue.Add
RPC正在连续完成:
ndb.context.py
中的一点点挖掘表明put_async()
调用最终会被添加到AutoBatcher
而不是立即发出的RPC。
所以我假设当_put_batcher
等待所有异步调用完成时,toplevel
最终会被刷新。
我知道批处理put在某些情况下有实际的好处,但在我的情况下,我真的希望立即发送put RPC,所以我可以在保存实体时执行其他工作。
如果我yield foo.put_async()
,那么我会在Appstats中获得相同的瀑布,但在其余时间内完成datastore.Put
:
这是预期的,因为yield
使我的处理程序在执行其余代码之前等待put_async()
调用完成。
我也尝试在ndb.get_context().flush()
之后立即添加对foo.put_async()
的调用,但根据Appstats,datastore.Put
和taskqueue.BulkAdd
调用仍然没有并行调用。< / p>
所以我的问题是:如何强制调用put_async()
来绕过自动批处理程序并立即发出RPC?
答案 0 :(得分:6)
没有受支持的方式来做到这一点。也许应该有。你能试试这个吗?
loop - ndb.eventloop.get_event_loop()
while loop.run_idle():
pass
您可能需要查看ndb / eventloop.py的源代码以查看您还可以尝试的其他内容 - 基本上您想要尝试run0()所做的大部分工作,除非等待RPC。特别是,您可能必须这样做:
while loop.current:
loop.run0()
while loop.run_idle():
pass
(这仍然不受支持,因为您可能还需要处理其他条件,但您的示例中似乎没有这些条件。)
答案 1 :(得分:-2)
试试这个,我不是100%肯定会有所帮助:
foo = yield Foo.get_by_id_async(some_id)
future = foo.put_async()
future.done()
ndb请求被放入autobatcher,当需要结果时,批处理将被发送到RPC。由于您不需要foo.put_async()的结果,因此在您进行另一次ndb调用(您没有)或@ ndb.toplevel结束之前,它不会被发送。
调用future.done()不会阻止,但我猜它可能会触发请求。
尝试强制操作的另一件事是:
ndb.get_context().flush()