2012-03-28 42 views
0

在我的應用程序中,我需要一個處理函數來獲得一堆實體併爲它們中的每一個執行一個函數。並行代碼執行python2.7 ndb

我有我需要的所有實體的鑰匙。在獲取它們之後,我需要爲它們中的每一個執行1或2個實例方法,這會讓我的應用程序變慢。爲100個實體做這個需要大約10秒,這是減速的方式。

即時通訊試圖找到一種方法來獲取實體並執行這些功能並行以節省時間,但我不知道哪種方式是最好的。

我試過了_post_get_hook,但我有一個未來的對象,需要調用get_result()並在鉤子中執行該函數,在sdk中工作得很好,但獲得了很多'超過最大遞歸深度時調用Python對象「,但我不能真正明白爲什麼,錯誤信息不是很精細。

是管道api或ndb.Tasklets什麼即時通訊搜索?

atm即時通過試驗和錯誤,但我會很高興,如果有人可以讓我走向正確的方向。

編輯

我的代碼是類似於一個文件系統的東西,每個文件夾包含其他文件夾和文件。爲另一個實體設置集合的路徑,以便序列化一個集合實體,我需要獲取引用的實體並獲取路徑。在集合上,serialized_assets()函數越慢,其包含的實體越多。如果我可以並排執行每個包含的資產的序列化函數,它會加速相當多的事情。

class Index(ndb.Model): 
    path = ndb.StringProperty() 


class Folder(ndb.Model): 
    label = ndb.StringProperty() 
    index = ndb.KeyProperty() 

    # contents is a list of keys of contaied Folders and Files 
    contents = ndb.StringProperty(repeated=True)  

    def serialized_assets(self): 
     assets = ndb.get_multi(self.contents) 

     serialized_assets = [] 
     for a in assets: 
      kind = a._get_kind() 
      assetdict = a.to_dict() 
      if kind == 'Collection': 
       assetdict['path'] = asset.path 
       # other operations ... 
      elif kind == 'File': 
       assetdict['another_prop'] = asset.another_property 
       # ... 
      serialized_assets.append(assetdict) 

     return serialized_assets 

    @property 
    def path(self): 
     return self.index.get().path 


class File(ndb.Model): 
    filename = ndb.StringProperty() 
    # other properties.... 

    @property 
    def another_property(self): 
     # compute something here 
     return computed_property 

EDIT2:

@ndb.tasklet 
    def serialized_assets(self, keys=None): 
     assets = yield ndb.get_multi_async(keys) 
     raise ndb.Return([asset.serialized for asset in assets]) 

是這個任務蕾代碼好嗎?

+0

這些函數是否很慢,因爲它們執行大量計算,或者因爲它們在RPC上等待?如果前者,線程或任務隊列是你最好的選擇;如果是後者,NDB tasklet是你想要的。詳細闡述,我可以發表任何一個答案。 – 2012-03-29 09:25:52

+0

@NickJohnson主要是等待RPC。我編輯了更多細節的問題。 – aschmid00 2012-03-29 13:56:46

回答

2

由於大部分函數的執行時間都用於等待RPC,所以NDB的異步和tasklet支持是您最好的選擇。這在一些詳細的描述here。爲您的要求最簡單的用法可能是使用ndb.map功能,這樣(從文檔):

@ndb.tasklet 
def callback(msg): 
    acct = yield ndb.get_async(msg.author) 
    raise tasklet.Return('On %s, %s wrote:\n%s' % (msg.when, acct.nick(), msg.body)) 

qry = Messages.query().order(-Message.when) 
outputs = qry.map(callback, limit=20) 
for output in outputs: 
    print output 

回調函數被調用查詢返回的每一個實體,它可以做到這一點,需要的任何操作(使用_async方法和yield異步執行它們),完成後返回結果。因爲回調是一個tasklet,並使用yield來進行異步調用,NDB可以並行運行多個實例,甚至可以批量增加一些操作。

+0

我不認爲我可以使用地圖,因爲我在我已經知道的鍵列表上使用ndb.get_multi()(或者至少我沒有看到有關使用ndb.get_multi()的地圖的任何文檔)。 – aschmid00 2012-03-29 14:52:30

+0

我認爲有幾個拼寫錯誤或者老文檔:ndb.get_async(msg.author)應該是msg.author.get_async()和tasket.Return是ndb.Return ...?! – aschmid00 2012-03-29 15:06:42

+0

acct是一個Future對象,所以試圖在字符串格式化中返回引發AttributeError:'Future'對象沒有屬性'nick' – aschmid00 2012-03-29 15:14:36

0

管道API對於你想要做的事情來說是過量的。你有什麼理由不能只使用taskqueue?

使用初始請求獲取所有實體密鑰,然後爲具有任務的每個密鑰執行每個實體的2個函數的任務。併發性將基於爲該任務隊列配置的併發請求數。