I'm loading templates from a coroutine in Tornado using
It's true, the first time a given template is read from the disk, it blocks Tornado's event loop:
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
This initial load is probably fast, since the template is likely only a few kilobytes and already loaded into the machine's in-memory filesystem cache. Subsequent accesses of the same template by the same Tornado process are cached within Tornado itself:
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]
So it doesn't seem worthwhile for Tornado to defer the filesystem access to a thread.
Often in Python async frameworks you'll see that not all I/O is performed asynchronously - quick and predictable blocking operations like accessing a file or a MySQL query might not block the loop long enough to worry about. What's critical is that long or unpredictable operations, like calling a remote HTTP service, are scheduled on the event loop.