2

我正在尝试围绕异步 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 添加到我的获取请求处理程序中。而且速度更快!

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

4

1 回答 1

4

如果您不等待结果从“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

于 2012-02-29T23:06:55.217 回答