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

时间:2013-02-21 14:59:51

标签: google-app-engine app-engine-ndb

我有一个请求处理程序,它更新实体,将其保存到数据存储区,然后需要在返回之前执行一些额外的工作(比如排队后台任务和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正在连续完成:

Appstats screenshot

ndb.context.py中的一点点挖掘表明put_async()调用最终会被添加到AutoBatcher而不是立即发出的RPC。

所以我假设当_put_batcher等待所有异步调用完成时,toplevel最终会被刷新。

我知道批处理put在某些情况下有实际的好处,但在我的情况下,我真的希望立即发送put RPC,所以我可以在保存实体时执行其他工作。

如果我yield foo.put_async(),那么我会在Appstats中获得相同的瀑布,但在其余时间内完成datastore.Put

2nd Appstats screenshot

这是预期的,因为yield使我的处理程序在执行其余代码之前等待put_async()调用完成。

我也尝试在ndb.get_context().flush()之后立即添加对foo.put_async()的调用,但根据Appstats,datastore.Puttaskqueue.BulkAdd调用仍然没有并行调用。< / p>

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

2 个答案:

答案 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()