导航

用户指南

非阻塞异步IO

实时Web功能需要每个用户保持大部分时间为空闲状态的长连接。在传统的同步Web服务器中,这意味着将一个线程投入到每个用户,这可能非常昂贵。

为了最小化并发连接的成本,Tornado使用单线程事件循环。这意味着所有应用程序代码都应该是异步和非阻塞的,因为一次只能有一个操作处于活动状态。

术语异步和非阻塞是密切相关的,并且通常可以互换使用,但它们并不完全相同。

阻塞

函数在返回之前等待某事发生时会阻塞。一个函数可能由于多种原因而阻塞:网络I/O,磁盘I/O,互斥体等。事实上,每个函数在运行和使用CPU时都会至少有一点阻塞(对于一个极端的例子来说明为什么CPU阻塞必须像其他类型的阻塞一样严肃,考虑密码散列函数,如bcrypt,它设计使用数百毫秒的CPU时间,远远超过典型的网络或磁盘访问)。

函数可以在某些方面阻塞,在其他方面非阻塞。在Tornado的上下文中,我们通常谈论在网络I/O的上下文中阻塞,尽管要最小化所有类型的阻塞。

异步

通常会在触发一些后续操作之前导致某些后台工作发生(这是相对于正常的异步函数来说,正常的异步函数会在return之前做完它们要做的所有事情)。有很多种不同种类的异步接口:

  • 参数回调(Callback argument)
  • 返回占位符(Future,Promise,Deferred)
  • 送入队列
  • 注册回调(例如POSIX信号)

无论使用哪种类型的接口,定义的异步函数与其调用者的交互方式都不同,没有一种自由的方式可以使同步函数以对其调用者透明的方式实现异步(像gevent这样的系统使用轻量级线程来提供与异步系统相当的性能,但它们实际上并没有实现异步)。

Tornado中的异步操作通常返回占位符对象(Futures),但一些低级别组件除外,比如IOLoop中就使用回调。Futures通常会通过awaityield关键字返回结果。

例子

下面是一个同步函数的例子:

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

async def asynchronous_fetch(url):
    http_client = AsyncHTTPClient()
    response = await http_client.fetch(url)
    return response.body

或者为了与旧版本的Python兼容,使用tornado.gen模块:

from tornado.httpclient import AsyncHTTPClient
from tornado import gen

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

协程是不是看上去有点神奇,但他们内部做的是这样的:

from tornado.concurrent import Future

def async_fetch_manual(url):
    http_client = AsyncHTTPClient()
    my_future = Future()
    fetch_future = http_client.fetch(url)
    def on_fetch(f):
        my_future.set_result(f.result().body)
    fetch_future.add_done_callback(on_fetch)
    return my_future

请注意,协程在获取完成之前返回其Future。 这是协程异步的原因。

你可以通过传递回调对象来执行协程所能做的任何事情,但协程可以像写同步代码一样实现异步功能,这样可以简化我们的代码。这对于错误处理尤为重要,因为try/except块的工作方式与协程中的预期相同,而回调很难实现。

协程将在本指南的下一部分中进行深入讨论。

上一篇:简介

下一篇:协程

最新Tornado5.11官方文档翻译(2)-用户手册-非阻塞异步IO
Tagged on:

发表评论

邮箱地址不会被公开。 必填项已用*标注