如何覆盖异步NDB方法并编写自己的tasklet

时间:2012-04-04 19:22:45

标签: python google-app-engine

我正在尝试掌握NDB引入的异步操作,我想使用@ndb.tasklet来同步我的一些工作。

简单的例子是被覆盖的get_or_insert_async

中的string_id生成

这是对事物的正确方法吗?这里可以改进什么?

@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

编辑:

新修订版......

@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

1 个答案:

答案 0 :(得分:1)

如果你想做的只是用不同的参数调用异步,你不需要使用tasklet - 只需返回包装函数的返回值,如下所示:

def get_or_insert_async(cls, *args):
  id = cls.make_string_id(*args)
  return super(MyModel, cls).get_or_insert_async(id)
但是,由于以下几个原因,我会对此持谨慎态度:你正在改变内置函数的含义,这通常是一个坏主意,你正在改变签名(位置参数但没有关键字参数),并且您没有将额外的参数传递给原始函数。

对于你的第二个例子,一次产生一个东西将迫使NDB等待完成 - 'yield'与'wait'同义。相反,为集合中的每个元素执行tasklet函数,然后同时等待它们(通过在列表上调用yield)。