2012-03-28 7 views
0

私のアプリでは、ハンドラの1つのエンティティの束を取得し、それぞれの関数を実行する必要があります。並列コードの実行python2.7 ndb

私は必要なすべてのエンティティの鍵を持っています。それらをフェッチした後、私はそれぞれの1つまたは2つのインスタンスメソッドを実行する必要があり、これは私のアプリケーションをかなり減速さ​​せます。これを100個のエンティティに対して行うには約10秒かかりますが、それは遅くなります。

エンティティを取得してそれらの関数を並列に実行して時間を節約する方法を見つけようとしていますが、どの方法が最良かはわかりません。

私は_post_get_hookを試しましたが、将来のオブジェクトがあり、get_result()を呼び出してsdkでokのように機能するフックで関数を実行する必要がありますが、最大再帰深度を超えると、 Python objec 'が、私は本当にundestandできない、なぜ、エラーメッセージは本当に精巧ではありません。

はパイプラインAPIまたはndb.Taskletsです。何を検索していますか?

atm imは試行錯誤していますが、誰かが私を正しい方向に導くことができれば嬉しいです。

EDIT

私のコードは、ファイルシステムに似たもので、すべてのフォルダは他のフォルダとファイルが含まれています。他のエンティティに設定されたコレクションのパスは、コレクションエンティティをシリアル化するために、参照されたエンティティを取得してパスを取得する必要があります。コレクションでは、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のタスクレットが必要なものです。精巧で、どちらかを示す答えを投稿することができます。 –

+0

@NickJohnsonはRPCを待っています。私は詳細を編集して質問を編集しました。 – aschmid00

答えて

2

あなたの関数の実行時間のほとんどは、RPCのを待って費やされているので、NDBの非同期タスクレットとサポートは、あなたの最善の策です。これについては、詳細は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を使用します)、完了したら結果を返します。コールバックはタスクレットであり、yieldを使用して非同期呼び出しを行うため、NDBは複数のインスタンスを同時に実行し、さらにいくつかの操作を一括して実行できます。

+0

私は既に知っているキーのリスト(または少なくともndb.get_multi()で​​マップを使用することについてのいかなる文書も見ていない)でndb.get_multi()を使用するのでマップを使用できるとは思わない。 – aschmid00

+0

いくつかのタイプミスや古いドキュメントがあると思います。 – aschmid00

+0

acctはFutureオブジェクトですので、Returnで文字列の書式設定を試みるとAttributeErrorが発生します: 'Future'オブジェクトに 'nick'属性がありません – aschmid00

0

パイプラインAPIは、あなたが何をしたいのための過剰です。タスクキューを使用できない理由はありますか?

は、エンティティキーのすべてを取得するための最初の要求を使用して、タスクごとのエンティティ2つの機能を実行した各キーのためのタスクをキュー。並行処理は、そのタスクキューに対して構成されている並行要求の数に基づいて行われます。