我正在尝试掌握NDB引入的异步操作,我想使用@ndb.tasklet
来同步我的一些工作。
简单的例子是被覆盖的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
编辑:
新修订版......
@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
答案 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)。