bigywater.tech
Flask · 63

模板缓存

模板编译一次要几毫秒,所以 Jinja 会缓存。缓存在哪里、多大、什么时候失效?改了模板为什么有时不生效?这篇把缓存的每个开关都打开关上试一遍。

400
jinja_env 编译缓存的默认容量
18×
第一次请求(含编译)相对之后请求的耗时倍数
5.4×
auto_reload=True 相对 False 的缓存命中耗时

缓存命中

实测 · 本机执行输出
  get_template("t0.html") 3 次:加载器的 get_source 调用了 1 次;缓存里有 1 项;缓存键示例: ["(<weakref at 0x10aad5490; to 'Counting' at 0x10aa2e270>, 't0"]
  默认 auto_reload = True → 每次 get_template 都会检查文件是否被修改(uptodate)

上一篇:模板渲染异常处理;下一篇:Jinja2 Bytecode Cache。编译与渲染的耗时见Jinja2 Template Loader。

auto_reload 的代价

实测 · 本机执行输出
  auto_reload=True  缓存命中的 get_template:1.74 µs/次
  auto_reload=False 缓存命中的 get_template:0.32 µs/次

改文件后

实测 · 本机执行输出
  auto_reload=True  改前 '版本 1' → 改后 '版本 2'
  auto_reload=False 改前 '版本 1' → 改后 '版本 1'

缓存容量

实测 · 本机执行输出
  cache_size=400  10 轮 × 3 个模板 = 30 次 get_template,加载器读文件 3 次
  cache_size=2    10 轮 × 3 个模板 = 30 次 get_template,加载器读文件 30 次
  cache_size=400  轮流取 3 个模板:0.002 ms/轮
  cache_size=2    轮流取 3 个模板:1.407 ms/轮

关闭与清空缓存

实测 · 本机执行输出
  cache_size=0:get_template 5 次,读文件 5 次
  cache.clear() 之后再取:读文件 2 次(共 2 次:清之前 1 次 + 清之后 1 次)

Flask 的配置

实测 · 本机执行输出
  DEBUG=False TEMPLATES_AUTO_RELOAD=None  → jinja_env.auto_reload = False
  DEBUG=True  TEMPLATES_AUTO_RELOAD=None  → jinja_env.auto_reload = True
  DEBUG=False TEMPLATES_AUTO_RELOAD=True  → jinja_env.auto_reload = True
  DEBUG=True  TEMPLATES_AUTO_RELOAD=False → jinja_env.auto_reload = False
  先设 app.debug = False(这会创建 jinja_env),再设 TEMPLATES_AUTO_RELOAD = True → jinja_env.auto_reload = False (配置必须在 jinja_env 创建之前设好)

第一次请求

实测 · 本机执行输出
  第一次请求(含编译)1523 µs;之后每次 85 µs;第一次是之后的 18 倍

分步演示

模板缓存
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.7 / Flask 3.1.3 / Werkzeug 3.1.9 / Jinja2 3.1.6 / SQLAlchemy 2.1.1 / gunicorn 26.2.0(都装在自己的虚拟环境里);大多数实验用 Flask 的 test_client(直接调用 WSGI 应用,不经过网络),需要真实 HTTP 时另起 gunicorn 或开发服务器(端口 9600 以上,本机 127.0.0.1);计时用 time.perf_counter,数字每次运行会有小幅抖动
    • 没有验证:多线程下 LRUCache 的并发行为、模板缓存的内存占用、字节码缓存与内存缓存的叠加、gunicorn 多 worker 下每个进程各有一份内存缓存的占用
    京ICP备2026067502号-1京公网安备11010502063487号