BSSZDS930

博客园 首页 新随笔 联系 订阅 管理

阻塞

函数阻塞时会一直等待处理的结果才返回。阻塞情况比如网络I/O,硬盘I/O等。事实上,每一个函数都会阻塞,最少是一点点,因为他们在运行而且要使用Cpu(最有代表性的是密码hash函数bcrypt,要使用cpu的毫秒时间)。
一个函数在一些情况下会阻塞,但是在另外一些情况下不会阻塞。如tornado.httpclient 在DNS解决方案下,当采取默认的配置时会阻塞,但是在其他网络访问的情况下不会阻塞(比如使用ThreadedResolver 或tornado.curl_httpclient)。

异步

一个异步函数在函数结束之前就可以返回,通常在触发一些未来的动作之前会引起后台处理处理一些工作。下面有几种异步接口:

  • Callback 参数(回调函数)
  • 返回一个占位符(比如Future、Promise、Deferred)
  • 发送至一个队列中(Queue)
  • 回调注册(POSIX signals)

异步化

  • 给RequestHandler的请求处理函数添加@tornado.gen.coroutine装饰器
  • 给RequestHandler的请求处理函数添加@tornado.web.asynchronous装饰器
  • 使用@return_future装饰器
from tornado import gen

@gen.coroutine
def fetch_coroutine(url):
    http_client = AsyncHTTPClient()
    response = yield http_client.fetch(url)
    # 在Python 3.3之前, 在generator中是不允许有返回值的,必须通过抛出异常来代替. 如raise gen.Return(response.body).
    return response.body

在Tornado 5.x版本中,这几个装饰器都被标记为deprcated(过时),我们可通过Python3.5中引入的async和await(在Python3.7中已经成为正式关键字)来达到同样的效果。当然,要实现异步化还得靠其他的支持异步操作的三方库来支持,如果请求处理函数中用到了不支持异步操作的三方库,就需要靠自己写包装类来支持异步化。

  • Postgresql: asyncpg
  • Redis: aioredis
  • I/O Framework:uvloop

@gen.coroutine 与 @gen.engine

tornado.gen 支持以同步方式编写异步代码的核心就是 python generator。其原理简单来说,就是通过 generator.next() 启动 yield 返回的 generator ,通过 IOLoop 与 generator.send(value) 驱动 generator 运行,以达到协调异步执行的目的。

从功能上来看, @gen.coroutine 与 @gen.engine 的功能非常相似,差别就在于二者对被装饰方法参数中的 “callback” 参数处理不一样以及具有不同的返回值。

  • @gen.coroutine 装饰的方法执行后返回 Future 对象并且会将方法参数中的 “callback” 加入到 Future 完成后的回调列表中;
  • @gen.engine 装饰的方法执行后没有返回值(注:实际上如果被装饰方法有返回值,会抛出 ReturnValueIgnoredError 异常,详见后面的代码分析部分)。

所以,通过 @gen.engine 装饰的方法没有返回值,方法必须自己在异步调用完成后调用 “callback” 来执行回调动作,而通过 @gen.coroutine 装饰的方法则可以直接返回执行结果,然后由 gen 模块负责将结果传递给 “callback” 来执行回调。

@tornado.gen.coroutine + yield + raise gen.Return(d)

  • 当调用一个协程时,@tornado.gen.coroutine 与 yield 必须同时出现调用函数中
  • 如果只是在协程中执行操作或者直接返回结果,有 @tornado.gen.coroutine 和 return(raise Return)就够了
posted on 2020-05-25 15:31  BSSZDS930  阅读(229)  评论(0编辑  收藏  举报