如何重写一个异步NDB方法,写自己的tasklet
问题描述:
我试图把握与NDB介绍异步操作,我想用@ndb.tasklet
到异步我的一些工作。如何重写一个异步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
答
你并不需要使用微进程,如果所有你想要做的就是调用异步的东西用不同的参数 - 只返回被包装的函数的返回值,就像这样:
def get_or_insert_async(cls, *args):
id = cls.make_string_id(*args)
return super(MyModel, cls).get_or_insert_async(id)
我是持谨慎态度的原因很多,但:你改变的意义内置的功能,这通常是一个坏主意,你改变了签名(位置参数,但没有关键字参数) ,而且您不会将其他参数传递给原始函数。
对于你的第二个例子中,产生的东西一次一个将迫使NDB等待他们完成 - “成品率”与“等待”的代名词。相反,对集合中的每个元素执行tasklet函数,然后同时等待所有元素(通过调用列表中的yield)。
不可能将其在'get_or_insert_async'同步,只有底层调用原来'get_or_insert_async'真的异步'make_string_id'电话吗? – 2012-04-05 08:03:44
你可以在你的答案中重写第二个例子吗?我不确定女巫的产量是否下降,因此循环不会等待每个元素和所有(或大部分)内部并行处理的'internal_tasklet'执行。 – 2012-04-05 08:07:37
@WooYek是的,但make_string_id在你的代码片段中是同步的。如果他们没有制作RPC,那么异步执行它们就毫无意义 - 只有当时间用于RPC时,tasklet才有用。关于第二个例子 - 问题是在循环中调用yield的反模式。这样做等待每个单独的任务完成后再进入下一个任务。任何时候你有一个带有yield的循环,你应该调用没有yield的函数,汇总一个结果列表,并在该列表中调用yield。 – 2012-04-05 08:46:40