异步和非阻塞 I/O¶

    为了减小对于并发连接需要的开销,Tornado使用了一种单线程事件循环的方式.这意味着所有应用程序代码都应该是异步和非阻塞的,因为在同一时刻只有一个操作是有效的.

    异步和非阻塞这两个属于联系十分紧密而且通常交换使用,但是它们并不完全相同

    一个函数通常在它等待返回值的时候被 阻塞 .一个函数被阻塞可能由于很多原因:网络I/O,磁盘I/O,互斥锁等等.事实上, 每一个 函数都会被阻塞,只是时间会比较短而已,当一个函数运行时并且占用CPU(举一个极端的例子来说明为什么CPU阻塞的时间必须考虑在内,考虑以下密码散列函数像bcrypt, 这个函数需要占据几百毫秒的CPU时间,远远超过了通常对于网络和磁盘请求的时间).

    一个 异步 函数在它结束前就已经返回了,而且通常会在程序中触发一些动作然后在后台执行一些任务.(和正常的 同步 函数相比, 同步函数在返回之前做完了所有的事). 这里有几种类型的异步接口:

    • 返回一个占位符 (, Promise, Deferred)
    • 回调注册 (例如. POSIX 信号)
      不论使用哪一种类型的接口, 依据定义 异步函数与他们的调用者有不同的交互方式;但没有一种对调用者透明的方式可以将同步函数变成异步函数 (像 gevent 通过一种轻量的线程库来提供异步系统,但是实际上它并不能让事情变得异步)

    一个简单的同步函数:

    这时同样的函数但是被通过回调参数方式的异步方法重写了:

    原始的 版本十分复杂, 但是 Futures 是 Tornado 中推荐使用的一种做法,因为它有两个主要的优势. 错误处理时通过Future.result 函数可以简单的抛出一个异常 (不同于某些传统的基于回调方式接口的一对一的错误处理方式), 而且 对于携程兼容的很好. 协程将会在本篇的下一节详细讨论. 这里有一个协程版本的实力函数, 这与传统的同步版本十分相似.

    语句 raise gen.Return(response.body) 在 Python 2 中是人为设定的,因为生成器不允许又返回值. 为了克服这个问题, Tornado 协程抛出了一个叫做 的特殊异常.协程将会像返回一个值一样处理这个异常.在 Python 3.3+ 中, return
    response.body
    将会达到同样的效果.

    原文: