tornado

2.2、User’s guide (Asynchronous a

2018-03-28  本文已影响26人  宝宝家的隔壁老王
Asynchronous and non-Blocking I/O
实时网络功能需要保持每个用户的长链接,传统的同步 web 服务器,这意味着给每个用户分配一个线程,代价是昂贵的。

为了将并发连接的成本降到最低,tornado 使用单线程事件循环。这意味着所有应用程序代码应该是异步非阻塞的,因为一次只能激活一个操作。

异步和非阻塞是密切相关的,通常可以互换使用,但是他们是不一样的。
Blocking
当一个函数在 return 前等待其他事情的发生时,就会阻塞。一个函数阻塞原因有很多:网络 I/O, 磁盘 I/O, 互斥锁等。事实上,每个函数在运行并且使用 CPU 的时候都会有一点阻塞(相比网络或磁盘访问可忽略不计)。

一个函数可以在某方面阻塞然后再另外方面不阻塞。在 tornado 背景下,我们通常谈论的是网络 I/O 阻塞,尽管各种阻塞都会被最小化。
Asynchronous
异步函数在它完成前就 return 了,在触发应用的未来事件时通常要在后台进行一些工作(不像正常的同步函数,在 return 前完成所有的事)。

异步接口有很多风格:
无论使用哪种类型的接口被使用,调用方式也不相同。调用者没有免费的方式将同步函数变成异步函数 (系统如 gevent 使用轻量级的线程提供性能和异步系统,但是他们实际上没有让事情异步)
Examples
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)
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 版本更复杂,但 Future 在 tornado 中仍然被推荐,因为他有2个主要的优势。

错误处理在未来更加一致,因为 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 的表述,因为此时生成器不允许使用 return。

为了克服这一点,tornado 使用特殊的异常类型叫 Return。协程捕捉到这个异常,然后当做 return 处理。

在 python 3.3 及其以后,可以直接使用 return response.body 起到相同的作用。

下一篇: 2.3、User’s guide (Queue)
上一篇: 2.1、User’s guide (Introduction)

上一篇 下一篇

猜你喜欢

热点阅读