使用tornado的coroutine进行编程

Gen.coroutine原理

在之前一篇博客中讲到要使用tornado的异步特性,必须使用异步的库。否则单个进程阻塞,根本不会达到异步的效果。 Tornado的异步库中最常用的就是自带的AsyncHTTPClient。

在3.0版本之后,gen.coroutine模块显得比较突出。coroutine装饰器可以让本来靠回调的异步编程看起来像同步编程。其中便是利用了Python中生成器的Send函数。在生成器中,yield关键字往往会与正常函数中的return相比。它可以被当成迭代器,从而使用next()返回yield的结果。但是生成器还有另外一个用法,就是使用send方法。在生成器内部可以将yield的结果赋值给一个变量,而这个值是通过外部的生成器client来send的。举一个例子:

def test_yield():
    pirnt "test yeild"
    says = (yield)
    print says

if __name__ == "__main__":
    client = test_yield()
    client.next()
    client.send("hello world")

输出结果如下:

test yeild
hello world

已经在运行的函数会挂起,直到调用它的client使用send方法,原来函数继续运行。而这里的gen.coroutine方法就是异步执行需要的操作,然后等待结果返回之后,再send到原函数,原函数则会继续执行,这样就以同步方式写的代码达到了异步执行的效果。

Tornado异步编程

@gen.coroutine
def post(self):
    client = AsyncHTTPClient()
    resp = yield client.fetch("https://api.github.com/users")
    if resp == 200:
        body = escape.json_decode(resy.body)
    else:
        body = {"message": "client fetch error"}
        logger.error("client fetch error %d, %s" % (resp.code, resp.message))
    self.write(escape.json_encode(body))
    self.finish()

换成函数之后可以变成这样;

@gen.coroutime
def post(self):
    resp = yield GetUser()
    self.write(resp)

@gen.coroutine
def GetUser():
    client = AsyncHTTPClient()
    resp = yield client.fetch("https://api.github.com/users")
    if resp.code == 200:
        resp = escape.json_decode(resp.body)
    else:
        resp = {"message": "fetch client error"}
        logger.error("client fetch error %d, %s" % (resp.code, resp.message))
    raise gen.Return(resp)

这里,当把异步封装在一个函数中的时候,并不是像普通程序那样使用return关键字进行返回,gen模块提供了一个gen.Return的方法。是通过raise方法实现的。这个也是和它是使用生成器方式实现有关的。

你可能感兴趣的:(web开发)