2

@ndb.taskletNDB で導入された非同期操作を把握しようとしています。自分の作業の一部を非同期に使用したいと考えています。

簡単な例は、オーバーライドされた string_id の生成です。get_or_insert_async

これは物事への正しい方法ですか?ここで何を改善できますか?

@classmethod
@ndb.tasklet
def get_or_insert_async(cls, *args):
    id = cls.make_string_id(*args) 
    model = yield super(MyModel, cls).get_or_insert_async(id)
    raise ndb.Return(model)

別の例は、ファンアウトのような方法でループ内で何かを行うことです。これは正しいです?

@classmethod
@ndb.tasklet
def do_stuff(cls, some_collection):

    @ndb.tasklet
    def internal_tasklet(data):
        do_some_long_taking_stuff(data)
        id = make_stuff_needed_for_id(data)
        model = yield cls.get_or_insert_async(id)
        model.long_processing(data)
        yield model.put_async()
        raise ndb.Return(None)

    for data in some_collection:
        # will it parallelise internal_tasklet execution? 
        yield internal_tasklet(data)

    raise ndb.Return(None)

編集:

全体の概念が理解されているように、(可能な場合) 並行して収集され、非同期的に実行されるオブジェクトをyields提供するためにここにあります。Future私は正しいですか?

ニックのヒントの後 (それはあなたが意図したものですか?):

@classmethod
@ndb.tasklet
def do_stuff(cls, some_collection):

    @ndb.tasklet
    def internal_tasklet(data):
        do_some_long_taking_stuff(data)
        id = make_stuff_needed_for_id(data)
        model = yield cls.get_or_insert_async(id)
        model.long_processing(data)
        raise ndb.Return(model)                # change here

    models = []
    for data in some_collection:
        # will it parallelise internal_tasklet execution? 
        m = yield internal_tasklet(data)       # change here
        models.appedn(m)                       # change here

    keys = yield ndb.put_multi_async(models)   # change here
    raise ndb.Return(keys)                     # change here

編集:

新しい改訂版…</p>

@classmethod
@ndb.tasklet
def do_stuff(cls, some_collection):

    @ndb.tasklet
    def internal_tasklet(data):
        do_some_long_taking_stuff(data)
        id = make_stuff_needed_for_id(data)
        model = yield cls.get_or_insert_async(id)
        model.long_processing(data)
        raise ndb.Return(model)                

    futures = []
    for data in some_collection:
        # tasklets won't run in parallel but while 
        # one is waiting on a yield (and RPC underneath)  
        # the other will advance it's execution 
        # up to a next yield or return
        fut = internal_tasklet(data))          # change here
        futures.append(fut)                    # change here

    Future.wait_all(futures)                   # change here

    models = [fut.get_result() for fut in futures]
    keys = yield ndb.put_multi_async(models)   # change here
    raise ndb.Return(keys)                     # change here
4

1 に答える 1

1

異なる引数を使用して非同期で何かを呼び出すだけの場合は、タスクレットを使用する必要はありません。次のように、ラップされた関数の戻り値を返すだけです。

def get_or_insert_async(cls, *args):
  id = cls.make_string_id(*args)
  return super(MyModel, cls).get_or_insert_async(id)

ただし、これについてはいくつかの理由で注意が必要です。組み込み関数の意味を変更しますが、これは通常は悪い考えです。署名(位置引数は変更しますが、キーワード引数は変更しません)を変更します。元の関数に余分な引数を渡さないでください。

2番目の例では、一度に1つずつ生成すると、NDBは完了を待機するように強制されます。「yield」は「wait」と同義です。代わりに、コレクション内の各要素に対してタスクレット関数を実行してから、(リストでyieldを呼び出して)すべての要素を同時に待機します。

于 2012-04-05T04:24:49.093 に答える