2012-02-29 2 views
2

Я пытаюсь обвести голову асинхронным api без особого успеха.NDB Async API и get_or_insert_async

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

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

И метод, который использует get_or_insert и проверки, если reference_list содержит ключ, если не добавить его. Под объектом является модель сущность и список представляет собой список строк [ «ABC», «DEF», «ГХИ»]

@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) 

Это работало, как я хотел, но к looong времени. Если список был около 20-30 раз. Это заняло около 15-20 секунд.

Итак, я начал смотреть асинхронный апи. Но не очень далеко. Теперь он не хранит вещи в БД:

@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) 

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

EDIT:

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

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

+1

Я подробно расскажу в списке appengine-ndb-discuss. –

ответ

4

Если вы не ждать результата, чтобы вернуться из вашего «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

+0

Ты абсолютно прав. Но я в конечном итоге использовал @ ndb.toplevel, что, я думаю, что-то подобное. Обновленный вопрос с решением, которое я закончил с помощью upp. – fredrik

+0

Печальная часть состоит в том, что я технический писатель, который написал документацию, из-за которой было так сложно обернуть мозг вокруг этого в первую очередь. Поэтому, если у вас есть предложения о том, как сделать эту мозговую упаковку проще, пожалуйста, говорите. –

+0

В основном я бы сказал, что делают разные декораторы, и разница между ними. Также еще несколько примеров. Например, наилучшая практика использования тарелки и использования .get_result. Возможно, это не самое лучшее место для обсуждения этого. Не удалось найти ваш адрес электронной почты, но если бы вы могли оставить мне один (почта в профиле), у меня есть несколько (я думаю) хороших идей, как улучшить это. – fredrik