2

私は非同期APIに頭を悩ませようとしていますが、あまり成功していません。

私のラボプロジェクトでは、かなり単純なセットアップです。次のようなモデルがあります。

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)

これは私が望んでいたように機能しましたが、時間がかかりました。リストの長さが約 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)

主にタスクレットとyieldの概念を理解していないため、どこにあるのかよくわかりません。誰でも何か考えがありますか、それとも私を方向に向けることができますか?

編集:

私はこの解決策になりました:

@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-request ハンドラーに追加します。そして、それはずっと速いです!

また、この質問をhttps://groups.google.com/forum/?fromgroups#!topic/appengine-ndb-discuss/L4DEsYdEwTEに投稿し、いくつかのフォローアップの質問を含めました

4

1 に答える 1

4

「ndb.put_multi_async(put_queue)」から結果が返されるのを待たないと、Webハンドラーが実際にリクエストを実行する前に終了する可能性があります。put_multi_async関数の戻り値を確認してください。先物のリストです。

1つのFutureが終了するのを待つには、fut.get_result()(または、戻り値を気にしない場合はfut.wait())と言うことができます。先物がたくさんある場合は、 http: //code.google.com/appengine/docs/python/ndb/futureclass.htmlで説明されているFuture.wait_allwait_anyが必要になる可能性があります。

于 2012-02-29T23:06:55.217 に答える