tornado.web.RequestHandler.render_string() 如何在不阻塞整个应用程序的情况下加载模板?

How does tornado.web.RequestHandler.render_string() load a template without blocking the whole application?

我正在使用 render_string() 从 Tornado 中的协程加载模板,我想到 render_string() 不是协程。所以我们正在从一个协程访问磁盘,但我们没有产生任何未来。我想知道它是如何工作的,它是否会阻止应用程序。

是的,第一次从磁盘读取给定模板时,它会阻塞 Tornado 的事件循环:

class Loader(BaseLoader):
    def _create_template(self, name):
        path = os.path.join(self.root, name)
        with open(path, "rb") as f:
            template = Template(f.read(), name=name, loader=self)
            return template

这个初始加载可能很快,因为模板可能只有几千字节,并且已经加载到机器的内存文件系统缓存中。同一 Tornado 进程对同一模板的后续访问缓存在 Tornado 本身中:

class BaseLoader(object):
    def load(self, name, parent_path=None):
        """Loads a template."""
        name = self.resolve_path(name, parent_path=parent_path)
        with self.lock:
            if name not in self.templates:
                self.templates[name] = self._create_template(name)
            return self.templates[name]

因此,Tornado 将文件系统访问延迟到线程似乎并不值得。

通常在 Python 异步框架中,您会发现并非所有 I/O 都是异步执行的 - 快速且可预测的阻塞操作(例如访问文件或 MySQL 查询)可能不会阻塞循环够长不用担心。关键是长时间或不可预测的操作,如调用远程 HTTP 服务,被安排在事件循环上。