Асинхронный API NDB и get_or_insert_async

Я пытаюсь разобраться с асинхронным 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)

Я действительно не понимаю, где, в основном потому, что я не понимаю концепцию тасклетов и доходности. У кого-нибудь есть идея или может указать мне направление?

ИЗМЕНИТЬ:

Я закончил с этим решением:

@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 и содержит несколько дополнительных вопросов.


person fredrik    schedule 29.02.2012    source источник
comment
Я подробно отвечаю на список appengine-ndb-discuss.   -  person Guido van Rossum    schedule 02.03.2012


Ответы (1)


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

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

person Larry Hosken    schedule 29.02.2012
comment
Вы абсолютно правы. Но в итоге я использовал @ndb.toplevel, который, я думаю, делает что-то подобное. Обновил вопрос с решением, которое я использовал. - person fredrik; 01.03.2012
comment
Печально то, что я технический писатель, написавший документацию, из-за которой вам было так трудно понять это в первую очередь. Так что, если у вас есть предложения, как облегчить эту загрузку мозгов, пожалуйста, выскажитесь. - person Larry Hosken; 01.03.2012
comment
В основном я бы сказал, что делают разные декораторы, и в чем разница между ними. Также еще несколько примеров. Например, лучшая практика, когда использовать тасклет и когда использовать .get_result. Возможно, это не лучшее место для обсуждения этого. Не удалось найти вашу электронную почту, но если бы вы могли написать мне (почта в профиле), у меня есть несколько (я думаю) хороших идей, как это улучшить. - person fredrik; 01.03.2012
comment
Да, действительно, это хорошие идеи, спасибо. Я не вижу адреса электронной почты в вашем профиле (может быть, stackoverflow скрывает их, чтобы предотвратить злоупотребления?), но если вам есть что сказать, вы можете связаться со мной по адресу [email protected] . Спасибо! - person Larry Hosken; 01.03.2012
comment
возможно :) Я нашел ваш адрес электронной почты (что-то в Интернете + комментарии). Но я перешлю его на ваш адрес Google. - person fredrik; 01.03.2012