新App Engine Datastore API介绍:Datastore Plus
2011 1 8 06:12 PM 2345次查看
分类:Google App Engine 标签:Google App Engine, Python
这个API采用全新的设计,突出了异步执行这个特点,具体介绍可以参考文档。目前还没有全部完成(包括设计),因此接口仍然会修改,有需求的可以尽早向Guido提出。
由于接口仍会变动,这里我只简要介绍一下了。
要理解本文,你首先需要掌握Python的generator(生成器)和coroutine(协程)这2个概念(见PEP 342)。
当年我也花了一段时间才理解它,简单来说,一个函数里只要使用了yield表达式,那么它就是一个generator。调用这个generator的next()或send(None)方法时,它会执行函数代码直到第一个yield表达式,并将这个yield表达式的参数计算出来,返回给调用它的代码。接下来调用代码可以对返回值进行处理,然后再次调用next()或send(something)方法,这样函数就从上次yield的地方继续执行,并将something作为yield表达式的值(next()实际上相当于send(None)),然后执行到下一个yield表达式,继续返回这个表达式。最后,当generator执行return时,会抛出一个StopIteration异常,表示没有后续yield了,而调用它的代码需要捕捉这个异常,将其作为结束标记。(注:for语句也会自动调用generator的next()方法,并自动捕获StopIteration异常。)
这样看上去,代码就是在2个上下文中不断切换了,但它又不是线程这么大粒度的调度,因此就被称为协程了。
由于GAE中不能使用线程,回调方式也显得很复杂,因此Guido就利用了协程来实现异步RPC。也就是说,消费者协程(可理解为主要的逻辑代码)去调用生产者协程,生产者访问数据库,发送完请求后就立即切换回消费者协程。这样消费者就能调用多个生产者协程来同时访问多次数据库,并等待生产者们完成访问。如此一来,消费者协程无需依次等待每个生产者协程完成任务,而可以让它们并行执行,同时自己也能执行其他代码,最后再收集生产者们的完成情况。
理解这点后,剩下的部分也就很容易明白了。
你调用Datastore Plus提供的async函数时,它会请求数据库,然后返回一个Future对象。当你yield这个Future对象时,就能拿到返回结果了。
当然,你也可以同时执行多个async函数,然后再yield这些Future对象,这样就能达到并行执行的目的了。
不过要使用这些Future对象,还得配合使用tasklet。它是一个decorator,可以让你的函数变成一个generator,这样就能正确处理yield表达式了。
对于webapp.RequestHandler的get()方法来说,你可以用context.toplevel这个decorator;而一般的函数则使用tasklets.synctasklet;而如果要自己生成一个Future对象,则需要使用tasklets.tasklet,并且注意返回值是用raise tasklets.Return(value)这种方式。
其他就没什么好说的了,基本上都很好理解。
顺便给个例子程序,和前天的测试代码实现相同的功能:
from time import time
from ndb import model, tasklets
class Test(model.Model):
pass
@tasklets.synctasklet
def main():
keys = [model.Key('Test', i) for i in xrange(1, 501)]
tests = [Test(key=key) for key in keys]
t = time()
yield [test.put_async() for test in tests]
print time() - t
t = time()
f = Test.all().fetch_async(500)
fs = [key.get_async() for key in keys]
yield f
yield fs
print time() - t
t = time()
yield [key.delete_async() for key in keys]
print time() - t
if __name__ == '__main__':
main()
向下滚动可载入更多评论,或者点这里禁止自动加载。