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 服务,被安排在事件循环上。
我正在使用 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 服务,被安排在事件循环上。