bigywater.tech
Flask · 145

多进程下的全局变量

Flask 部署成多个进程之后,模块里的全局变量还可靠吗?--preload 改变了什么?进程内缓存的命中率会怎样?这篇用 4 个 gunicorn worker 与自己起的 redis,把每种现象量出来。

6、17 对 40
读到的进程内计数与真实总数(redis 里是 40)
4 → 1
--preload 前后,模块导入时算出的随机值的不同个数(4 个进程)
4 次
同一个 key 的进程内缓存被「现算」的次数(期望 1 次)

每个进程一份全局变量

实测 · 本机执行输出
  40 次 /inc 落在各进程的次数: [1, 6, 16, 17] (共 4 个进程)
  20 次读取看到的「全局计数」(进程号, 值): [(558, 6), (559, 17)]
  同一时刻读到的 local 值有 2 种,期望是 40 的只有 0 种;而 redis 里共享的计数始终是 {40}

上一篇:Gunicorn Worker 类型;下一篇:后台线程与 Application Context。

redis 是自己在非默认端口起的临时实例,验证完就关闭了。

导入时算的值与 --preload

实测 · 本机执行输出
  不加 --preload 看到 4 个进程,STARTUP_TOKEN 有 4 个不同的值
  --preload    看到 4 个进程,STARTUP_TOKEN 有 1 个不同的值

进程内缓存

实测 · 本机执行输出
  同一个 key 请求 40 次,「现算」了 4 次(每个进程第一次各算一次,期望只算 1 次)

放到进程外面

实测 · 本机执行输出
  (redis 的 INCR 是原子的,4 个进程各自 INCR,读到的是同一个总数)

分步演示

多进程下的全局变量
本步的对象

    本文用到的工具与边界

    • 本机 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,数字每次运行会有小幅抖动。gunicorn sync worker、redis-py 8.1.0、自己起的 redis
    • 没有验证:uwsgi 的 lazy-apps、preload 下数据库连接在 fork 之后的问题(第 91 篇的连接池)、multiprocessing 共享内存、文件锁、更多 worker 数量下的分布
    京ICP备2026067502号-1京公网安备11010502063487号