Tornado 异步基本概念

Tornado async basic concepts

我正在尝试了解 Tornado 和异步的一些概念。如果我们有两个会话 X 和 Y 连接到 Tornado 服务器 T。

现在假设 X 执行阻塞 10 秒的数据库写入。在那段时间里,Y 向 T 请求某些东西。T 是否必须等到 X 完成写入才能得到服务?

我认为龙卷风会产生两个实例并分别处理它们从 X 切换到 Y?

Tornado 将运行 作为单线程并根据套接字事件在请求之间快速切换。如果编写正确,这是一种非常快速的服务请求方式,也是 Node.js 的工作方式。

但是,您需要确保 none 的操作在处理请求时处于阻塞状态,否则您会阻塞整个线程,从而阻塞整个龙卷风服务器。

您只能将 Tornado 与异步调用一起使用。例如,如果您正在发出 http 请求,则不能使用传统的阻塞式 HTTP 客户端。幸运的是 Tornado 为您提供了一个内置的异步库:

http://tornado.readthedocs.org/en/latest/httpclient.html

def handle_request(response):
    if response.error:
        print "Error:", response.error
    else:
        print response.body

http_client = AsyncHTTPClient()

# this line does not block! it immediately returns and you get the result later.
http_client.fetch("http://www.google.com/", handle_request)

Now suppose X performs a database write that is blocking for 10seconds.

与 HTTP 请求一样,您的数据库查询也不能被阻塞。在这种情况下,您将需要使用一个异步 MySQL 库,它会在您启动请求时立即 returns,并且 returns 您稍后会在回调中得到结果。

这是一个您可以使用的潜在库:

https://github.com/PyMySQL/Tornado-MySQL

之所以Node.js非常流行这种单线程范式,是因为最初Node.js只支持最多一个线程,所以所有官方数据库库,http库都是async的默认。使用 Python,您需要深入研究多个(有时是非官方的)库才能自己找到异步库。

编辑:

正如 Anthony 所提到的,如果您的数据库 queries/writes 很快(少于 10 毫秒),您应该可以发出阻塞请求。一切都结束了,你的表现开始受到影响。

tornado 能否以异步方式处理数据库连接取决于您使用的数据库库。对于要异步执行的数据库查询,他们必须使用 Tornado 的 IOLoop,否则 Tornado 将在发送数据库查询和收到响应时阻塞。

因此,在您的示例中,如果数据库库不使用底层 Tornado IOLoop,则 X 将阻塞 10 秒,Y(以及任何其他请求)将在数据库写入 X 完成后执行,但是如果数据库库确实使用了 Tornado IOLoop,并且您将 X 实现为异步处理程序,在执行数据库写入时产生,Y 可以在 Tornado 的 IOLoop 等待数据库对 X 的写入数据库请求的响应时进行处理。

作为 MongoDB 的示例,我在 Tornado 中使用了几个 ORM 库,MotorEngine (https://motorengine.readthedocs.org) and MongoEngine (https://mongoengine-odm.readthedocs.org)。 MongoEngine 不使用 Tornado IOLoop,因此所有调用都是阻塞的,MotorEngine 确实使用 IOLoop,因此您可以编写不阻塞的查询。

还有其他方法可以处理长 运行ning 任务(过去我设置了额外的网络服务并使用 AsyncHTTPClient 调用它们,我还使用了任务调度程序例如 Celery 将处理推送到后台,通常是在另一台服务器上)。然而,根据我的经验,数据库查询很少成为瓶颈,一个好的经验法则是尽量确保你尽可能快地保持它们,如果你不能,但希望我的回答是有用的。

回复。我认为龙卷风会产生两个实例并分别处理它们从 X 切换到 Y?

Tornado 不会生成多个实例来处理额外的请求,您可以 运行 Tornado 的多个实例(实际上根据我的经验和 Tornado 文档中的示例 - 这是可取的)。