0

私のアプリでは、ハンドラーの1つに対して、一連のエンティティを取得し、それぞれに対して関数を実行する必要があります。

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

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

私は _post_get_hook を試しましたが、将来のオブジェクトがあり、get_result() を呼び出してフックで関数を実行する必要があります。これは、sdk で正常に動作しますが、多くの「Python objec の呼び出し中に最大再帰深度を超えました」を取得しますが、理由がよくわかりませんし、エラーメッセージも詳しくありません。

Pipeline 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])

このタスクレットのコードは大丈夫ですか?

4

2 に答える 2

2

関数の実行時間のほとんどはRPCの待機に費やされるため、NDBの非同期およびタスクレットのサポートが最善の策です。これについては、ここで詳しく説明します。要件の最も簡単な使用法は、おそらく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はその複数のインスタンスを並行して実行でき、一部の操作をバッチ処理することもできます。

于 2012-03-29T14:06:57.683 に答える
0

パイプラインAPIは、やりたいことにはやり過ぎです。タスクキューだけを使用できなかった理由はありますか?

最初のリクエストを使用してすべてのエンティティキーを取得し、各キーのタスクをキューに入れて、タスクにエンティティごとに2つの機能を実行させます。同時実行性は、そのタスクキューに構成されている同時要求の数に基づきます。

于 2012-03-29T07:35:09.433 に答える