在Google App Engine中使用@ ndb.tasklet或@ ndb.synctasklet

Sno*_*man 10 python google-app-engine app-engine-ndb

我有一个POST调用几个tasklet的方法.这些tasklet确实有产量x.put_async(),我的代码中确实有一些.所以我不希望它在所有异步内容完成之前返回.所以我装饰了我的所有tasklet,它们只是小功能@ndb.tasklet.另外,除了我的POST方法,我还有:

@ndb.toplevel
def post(self):
Run Code Online (Sandbox Code Playgroud)

但是,在文档中它声明:

但是如果一个处理程序方法使用yield,那么该方法仍然需要包装在另一个装饰器中,@ ndb.synctasklet; 否则,它将停止执行收益而不完成.

的确,我的方法有收益率.它已经包含在@ ndb.tasklet中.我是用@ ndb.synctasklet替换它还是我同时使用它们(如果是这样,我将如何使用它们)?

另外,请参阅此线程有一些相关性.我也注意到一个问题,我的请求将返回没有任何输出,但是不可重现.它每15分钟左右就会持续使用.我app = ndb.toplevel(webapp2.WSGIApplication([..])只有,但现在我已经添加@ndb.toplevel到主要POST方法,但问题仍然存在.

我应该把@ndb.tasklet方法放在那些方法上put_async()吗?(为了安全起见,我应该把它放在每个方法的顶部吗?这有什么缺点?)

Rob*_*tis 10

关于处理程序和使用@ndb.toplevel和@ndb.synctasklet:我理解的方式是你需要在处理程序上同时使用@ ndb.synctasklet和@ ndb.toplevel.所有子tasklet只需要@ ndb.tasklet装饰器.例如

class Foo(ndb.Model):
    name = ndb.StringProperty()

    @ndb.tasklet
    def my_async(self):
        ....
        #do something else that yields
        raise ndb.Return("some result")   


@ndb.toplevel
@ndb.synctasklet
def post(self):
    foo = Foo(name="baz")
    yield foo.put_async()
    yield foo.my_async()
    ....
Run Code Online (Sandbox Code Playgroud)

然而.看看源代码,似乎@ ndb.toplevel实际上是一个synctasklet:

def toplevel(func):
  """A sync tasklet that sets a fresh default Context.

  Use this for toplevel view functions such as
  webapp.RequestHandler.get() or Django view functions.
  """
Run Code Online (Sandbox Code Playgroud)

在处理程序中运行带有yield并使用@ ndb.toplevel修饰的小测试似乎仍然有效,并且看起来您可以从处理程序中删除@ ndb.synctasklet.

关于是否应该在调用put_async()的方法中包含@ ndb.tasklet:如果你没有对put_async()产生影响,那么你不需要在周围的方法中包含@ ndb.tasklet(@ ndb.toplevel将处理从put_async()获取结果

  • 好的回复!规则可归纳如下:(1)如果函数使用"yield",它应该是ndb.tasklet,ndb.synctasklet或ndb.toplevel.(2)包装在ndb.tasklet中的函数返回一个Future(你可以产生它或者显式地调用get_result()).(3)ndb.synctasklet就像在ndb.tasklet中包装它,但隐式调用get_result().(4)ndb.toplevel就像ndb.synctasklet一样,但也等待所有挂起的操作完成. (14认同)