对 Python Tornado 的阻塞感到困惑

Confusion about Python Tornado's blocking

所以我理解了 Tornado 本身是非阻塞事件循环的基本思想 I/O,但是像数据库访问这样的阻塞 IO 操作将导致 Tornado 在这些操作期间阻塞。

我不明白的是为什么在非阻塞操作期间Tornado似乎是阻塞的。

我在处理程序中有以下代码:

class MyHandler(BaseHandler):

    def get(self):
        x = 0
        for i in xrange(0,500000000):
            x = i

        self.render("page_temp.html",
                    title="Page"
                    )

加载页面大约需要 20 秒。如果我打开另一个浏览器 window 并尝试加载任何其他页面,我会一直挂起,直到第 20 秒页面加载完毕。难道是因为两个请求都来自同一个用户?

您正在您的处理程序中直接进行长时间的、CPU 绑定操作。 tornado 是单线程的,这意味着它无法在不阻塞所有其他请求的情况下在事件循环线程中执行 CPU 绑定工作。如果您需要进行 CPU 绑定工作,则必须在后台线程或进程中进行。

为了让这个方法同时处理请求,它需要看起来像这样:

from concurrent.futures import ThreadPoolExecutor
from tornado import gen
from tornado.web import RequestHandler

executor = ThreadPoolExecutor(8) # 8 Threads in the pool

class ThreadPoolHandler(RequestHandler):

    def _do_loop(self):
        x = 0
        for i in xrange(0,500000000):
            x = i

    @gen.coroutine
    def get(self):
        yield executor.submit(self._do_loop) # Run through the loop without blocking tornado
        self.render("page_temp.html",
                    title="Page"
                    )

通过在后台线程中使用 ThreadPoolExecutor 到 运行 昂贵的 for 循环,tornado 可以在等待 CPU 工作的同时继续为其他请求提供服务完成。