Tornado 4.3文档翻译: 用户指南-异步和非阻塞I/O

译者说

Tornado 4.3于2015年11月6日发布,该版本正式支持Python3.5async/await关键字,而且用旧版本CPython编译Tornado一样可使用这两个关键字,这无疑是一种进步。其次,这是最后一个支持Python2.6Python3.2的版本了,在后续的版本了会移除对它们的兼容。如今网络上尚未Tornado4.3的中文文档,因此为了让更多的朋友能接触并学习到它,我开始了这个翻译项目,但愿感兴趣的小伙伴能够一块儿参与翻译,项目地址是tornado-zh on Github,翻译好的文档在Read the Docs上直接能够看到。欢迎Issues or PR。git

异步和非阻塞I/O

实时web功能须要为每一个用户提供一个多数时间被闲置的长链接,在传统的同步web服务器中,这意味着要为每一个用户提供一个线程,固然每一个线程的开销都是很昂贵的.github

为了尽可能减小并发链接形成的开销,Tornado使用了一种单线程事件循环的方式.这就意味着全部的应用代码都应该是异步非阻塞的,由于在同一时间只有一个操做是有效的.web

异步和非阻塞是很是相关的而且这两个术语常常交换使用,但它们不是彻底相同的事情.服务器

阻塞

一个函数在等待某些事情的返回值的时候会被 阻塞. 函数被阻塞的缘由有不少:网络I/O,磁盘I/O,互斥锁等.事实上 每一个 函数在运行和使用CPU的时候都或多或少会被阻塞(举个极端的例子来讲明为何对待CPU阻塞要和对待通常阻塞同样的严肃: 好比密码哈希函数bcrypt, 须要消耗几百毫秒的CPU时间,这已经远远超过了通常的网络或者磁盘请求时间了).网络

一个函数能够在某些方面阻塞在另一些方面不阻塞.例如, tornado.httpclient 在默认的配置下,会在DNS解析上面阻塞,可是在其余网络请求的时候不阻塞(为了减轻这种影响,能够用 ThreadedResolver 或者是经过正确配置 libcurltornado.curl_httpclient 来作).在Tornado的上下文中,咱们通常讨论网络I/O上下文的阻塞,尽管各类阻塞已经被最小化了.并发

异步

异步 函数在会在完成以前返回,在应用中触发下一个动做以前一般会在后台执行一些工做(和正常的 同步 函数在返回前就执行完全部的事情不一样).这里列举了几种风格的异步接口:curl

  • 回调参数异步

  • 返回一个占位符 (.Future, Promise, Deferred)async

  • 传送给一个队列函数

  • 回调注册表 (POSIX信号)

不论使用哪一种类型的接口, 按照定义 异步函数与它们的调用者都有着不一样的交互方式;也没有什么对调用者透明的方式使得同步函数异步(相似 gevent使用轻量级线程的系统性能虽然堪比异步系统,但它们并无真正的让事情异步).

例子

一个简单的同步函数:

from tornado.httpclient import HTTPClient

    def synchronous_fetch(url):
        http_client = HTTPClient()
        response = http_client.fetch(url)
        return response.body

把上面的例子用回调参数重写的异步函数:

from tornado.httpclient import AsyncHTTPClient

    def asynchronous_fetch(url, callback):
        http_client = AsyncHTTPClient()
        def handle_response(response):
            callback(response.body)
        http_client.fetch(url, callback=handle_response)

使用 Future 代替回调:

from tornado.concurrent import Future

    def async_fetch_future(url):
        http_client = AsyncHTTPClient()
        my_future = Future()
        fetch_future = http_client.fetch(url)
        fetch_future.add_done_callback(
            lambda f: my_future.set_result(f.result()))
        return my_future

Future 版本明显更加复杂,可是 Futures 倒是Tornado中推荐的写法.由于它有两个主要的优点.首先是错误处理更加一致,由于 Future.result 方法能够简单的抛出异常(相较于常见的回调函数接口特别指定错误处理),并且 Futures 很适合和协程一块儿使用.协程会在后面深刻讨论.这里是上面例子的协程版本,和最初的同步版本很像:

from tornado import gen

    @gen.coroutine
    def fetch_coroutine(url):
        http_client = AsyncHTTPClient()
        response = yield http_client.fetch(url)
        raise gen.Return(response.body)

raise gen.Return(response.body) 声明是在Python 2 (and 3.2)下人为执行的, 由于在其中生成器不容许返回值.为了克服这个问题,Tornado的协程抛出一种特殊的叫 Return 的异常. 协程捕获这个异常并把它做为返回值.在Python 3.3和更高版本,使用 return response.body 有相同的结果.

相关文章
相关标签/搜索