bigywater.tech
Flask · 64

Jinja2 Bytecode Cache

内存里的模板缓存在每次重启后都是空的,第一批请求要把用到的模板重新编译一遍。能不能把编译结果存到磁盘?效果多大?什么时候失效?这篇用 300 个模板和真实的 gunicorn 重启来量。

37.9×
300 个模板在新进程里首次渲染:有字节码缓存相对没有的加速
300 个
300 个模板对应的缓存文件数(每个模板一个)
1 个
修改 1 个模板后被重写的缓存文件数

没有缓存的启动

实测 · 本机执行输出
  第一个模板 5.80 ms;300 个模板共 1501.6 ms
  第一个模板 5.77 ms;300 个模板共 1467.2 ms
  第一个模板 5.82 ms;300 个模板共 1496.9 ms

上一篇:模板缓存;下一篇:模板中执行函数的性能问题。

FileSystemBytecodeCache

实测 · 本机执行输出
  第一次(缓存目录是空的,编译并写入):第一个 6.14 ms;300 个共 1540.5 ms
  缓存目录里生成了 300 个文件;示例文件名:__jinja2_01032688d7e35f30a38dfd7ac28e73b9ba3d38c4.cache;单个大小约 10181 字节;总计 2984 KiB
  之后的新进程(读缓存):第一个 0.21 ms;300 个共 39.7 ms
  之后的新进程(读缓存):第一个 0.21 ms;300 个共 39.5 ms
  之后的新进程(读缓存):第一个 0.20 ms;300 个共 39.5 ms
  300 个模板:无缓存中位数 1496.9 ms → 读缓存中位数 39.5 ms,快 37.9 倍

失效规则

实测 · 本机执行输出
  修改 page0.html 后加载 page0 与 page1:缓存目录里被重写的文件数 = 1(只有被修改的 page0)

在 Flask 里启用

实测 · 本机执行输出
  Flask 渲染一个模板后缓存目录里的文件: ['__jinja2_01032688d7e35f30a38df']

重启后的第一批请求

实测 · 本机执行输出
  无缓存                            新启动的服务器上,头 60 个不同页面的请求共 337 ms
  有磁盘缓存(首次启动,写入)                 新启动的服务器上,头 60 个不同页面的请求共 367 ms
  有磁盘缓存(再次启动,读取)                 新启动的服务器上,头 60 个不同页面的请求共 49 ms

分步演示

字节码缓存
本步的对象

    本文用到的工具与边界

    • 本机 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,数字每次运行会有小幅抖动
    • 没有验证:缓存目录在多个 worker 同时首次启动时的并发写入、容器只读文件系统下的缓存目录选择、MemcachedBytecodeCache、Jinja 版本升级后旧缓存文件的兼容(文件名含校验和,没有专门验证版本隔离)
    京ICP备2026067502号-1京公网安备11010502063487号