2012-02-29 37 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