【问题标题】:NDB Async API and get_or_insert_asyncNDB 异步 API 和 get_or_insert_async
【发布时间】:2012-02-29 18:54:17
【问题描述】:

我正试图围绕异步 api 进行思考,但没有取得多大成功。

我的实验室项目中的设置相当简单。我有一个看起来像这样的模型:

class SearchIndex(model.Model):
    name = model.StringProperty(required=True)
    reference_list = model.KeyProperty(repeated=True)

还有一个使用 get_or_insert 并检查 reference_list 是否包含键的方法,如果没有则添加它。实体下方是模型实体,列表是字符串列表 ["abc","def","ghi"]

@classmethod
    def store_list_in_index(cls, list, entity):
        put_queue = []

        for verb in list:
            index_entity = cls._SEARCH_INDEX_DB_MODEL.get_or_insert(verb, name=verb)
            if not entity.key in index_entity.reference_list:
                index_entity.reference_list.append(entity.key)
                put_queue.append(index_entity)

        if put_queue:
            ndb.put_multi_async(put_queue)

这如我所愿,但持续了很长时间。如果列表长约 20-30 倍。大约需要 15-20 秒。

所以我开始研究异步 api。但不要走得太远。现在它不会在数据库中存储任何东西:

@classmethod
def store_list_in_index(cls, list, entity):
    put_queue = []
    async_queue = []

    @tasklets.tasklet
    def txn(verb, entity):
        ent = yield cls._SEARCH_INDEX_DB_MODEL.get_or_insert_async(verb, name=verb)
        if not entity.key in ent.reference_list:
            ent.reference_list.append(entity.key)
            put_queue.append(ent)
        raise tasklets.Return(ent)

    for verb in list:
        en = txn(verb, entity)

    if put_queue:
        ndb.put_multi_async(put_queue)

我不太明白在哪里,主要是因为我不了解 tasklet 和 yield 的概念。任何人有任何想法或可以指出我的方向吗?

编辑:

我最终得到了这个解决方案:

@classmethod
@ndb.tasklet
def get_or_insert_index_entity(cls, verb):
    ent = yield cls._SEARCH_INDEX_DB_MODEL.get_by_id_async(verb)
    if not ent:
        key = ndb.Key(cls._SEARCH_INDEX_DB_MODEL, verb)
        ent = cls._SEARCH_INDEX_DB_MODEL(key=key, name=verb)
        yield ent.put_async()

    raise ndb.Return(ent)

@classmethod
@ndb.tasklet
def txn(cls, verb, entity):
    ent = yield cls.get_or_insert_index_entity(verb)
    if not entity.key in ent.reference_list:
        ent.reference_list.append(entity.key)
        yield ent.put_async()
    raise ndb.Return(ent)

@classmethod
def store_list_in_index(cls, list, entity):
    put_queue = []
    for verb in list:
        put_queue.append(cls.txn(verb, entity))

并将@ndb.toplevel 添加到我的get-request 处理程序中。而且速度更快!

我也在https://groups.google.com/forum/?fromgroups#!topic/appengine-ndb-discuss/L4DEsYdEwTE 上发布了这个问题,并包含了一些后续问题

【问题讨论】:

  • 我正在详细回复 appengine-ndb-discuss 列表。

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


【解决方案1】:

如果您不等待结果从“ndb.put_multi_async(put_queue)”返回,那么您的 Web 处理程序可能会在它真正开始发出请求之前完成。检查 put_multi_async 函数的返回值。这是一个期货清单。

要等待一个 Future 完成,您可能会说 fut.get_result() (或者如果您不关心返回值,则可以使用 fut.wait())。如果你有一堆期货,你可能想要http://code.google.com/appengine/docs/python/ndb/futureclass.html中描述的 Future.wait_all wait_any

【讨论】:

  • 你是绝对正确的。但我最终使用了我认为做类似事情的@ndb.toplevel。用我最终使用的解决方案更新了问题。
  • 可悲的是,我是技术作家,他编写的文档让你一开始就很难把这个问题包起来。因此,如果您对如何更轻松地进行大脑包装有任何建议,请说出来。
  • 主要说一下不同装饰器的作用,以及它们之间的区别。还有几个例子。例如最佳实践何时使用 tasklet 以及何时使用 .get_result。这可能不是讨论这个的最佳场所。找不到您的电子邮件,但如果您可以给我发一封(个人资料中的邮件),我有一些(我认为)好主意如何改进它。
  • 确实,这些都是好主意,谢谢。我在您的个人资料中看不到电子邮件地址(也许是 stackoverflow 隐藏了它们以防止滥用?),但如果您有更多要说的,可以通过 lahosken@google.com 与我联系。谢谢!
  • 可能 :) 我找到了你的电子邮件地址(som web+cmets 的东西)。但我会重新发送到你的谷歌地址。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-03
  • 2011-01-09
  • 1970-01-01
  • 2010-09-08
  • 1970-01-01
相关资源
最近更新 更多