NDB Async API и get_or_insert_async - PullRequest
       7

NDB Async API и get_or_insert_async

2 голосов
/ 29 февраля 2012

Я пытаюсь обернуть голову вокруг асинхронного API, но без особого успеха.

Я довольно простая установка в моем лабораторном проекте.У меня есть модель, которая выглядит следующим образом:

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

И метод, который использует get_or_insert и проверяет, содержит ли reference_list ключ, если не добавить его.Ниже сущности - это модельная сущность, а 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)

Я действительно не понимаю, где, в основном, потому что я не понимаю концепцию тасклетов и 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.И это намного быстрее!

Я также разместил этот вопрос на https://groups.google.com/forum/?fromgroups#!topic/appengine-ndb-discuss/L4DEsYdEwTE и включил некоторые дополнительные вопросы

1 Ответ

4 голосов
/ 01 марта 2012

Если вы не ждете, пока результат вернется из вашего «ndb.put_multi_async (put_queue)», тогда ваш веб-обработчик может завершить работу, прежде чем он действительно сможет выполнить запрос. Проверьте, что возвращаемое значение функции put_multi_async. Это список фьючерсов.

Чтобы дождаться завершения одного будущего, вы можете сказать fut.get_result () (или fut.wait (), если вам не важно возвращаемое значение). Если у вас есть куча фьючерсов, вы, вероятно, хотите, чтобы Future.wait_all wait_any был описан в http://code.google.com/appengine/docs/python/ndb/futureclass.html

...