新App Engine Datastore API介绍:Datastore Plus

标签:Google App Engine, Python

今天Guido van Rossum(Python的作者)公布了一个新的App Engine datastore API:Datastore Plus
这个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()

7条评论 你不来一发么↓ 顺序排列 倒序排列

    向下滚动可载入更多评论,或者点这里禁止自动加载

    想说点什么呢?