2012-02-29 40 views
2

我想绕过异步API,我的头,没有太多的成功。NDB异步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”,“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) 

这个工作,因为我想要的,但是到了looong时间。如果名单长约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我的GET请求处理器。而且速度更快!

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

+1

上描述的Future.wait_all wait_any。我正在详细回复appengine-ndb-discuss列表。 – 2012-03-01 21:10:13

回答

4

如果你不等待结果来自你的背“ndb.put_multi_async(put_queue)”,将您的网络处理程序可能完成之后才会发出请求。检查put_multi_async函数的返回值。这是一份期货清单。要等待一个Future的完成,你可以说fut.get_result()(或者fut.wait(),如果你不关心返回值的话)。如果您有一堆期货,您可能需要在http://code.google.com/appengine/docs/python/ndb/futureclass.html

+0

你绝对正确。但我最终使用了@ ndb.toplevel,我认为它做了类似的事情。使用我结束使用的解决方案更新了问题。 – fredrik 2012-03-01 07:12:56

+0

可悲的是,我是一位撰写文档的科技作家,他们很难把你的大脑放在首位。所以,如果你有关于如何使这个大脑包装更容易的建议,请说出来。 – 2012-03-01 13:45:40

+0

主要是我会说不同的装饰器做什么,以及它们之间的区别。还有几个例子。例如,何时使用tasklet以及何时使用.get_result的最佳做法。这可能不是铁饼这个最好的地方。找不到你的电子邮件,但如果你可以给我一个邮箱(邮件档案),我有几个(我认为)好主意,如何改善这一点。 – fredrik 2012-03-01 14:22:45