多进程下模块级global变量完全失效,因各worker拥有独立内存副本;正确做法是用multiprocessing.Manager()、Value等进程间共享机制或外部存储。

多进程 Worker 下的模块级 global 变量完全失效
直接在 app.py 里写 counter = 0,再用 global counter 在视图中修改——这在 gunicorn 多 worker(比如 --workers 4)下毫无意义。每个 worker 进程启动时都会加载一份独立的模块副本,counter 在 worker-1 里加到 100,worker-2 里的 counter 还是 0,彼此看不到对方的变更。
常见错误现象:
- 接口返回值忽高忽低,或始终为初始值
- 后台定时任务更新了变量,但 HTTP 请求读不到新值
- 日志显示“已更新”,但下次请求又回到旧状态
根本原因不是代码写错,而是 Python 进程隔离机制本身决定了模块级变量无法跨进程共享。
threading.Lock 对多进程无效,别白费力气
有人发现单进程多线程下用 threading.Lock 能保护字典读写,就照搬到 gunicorn 多 worker 场景——结果照样出错。因为 threading.Lock 只在当前进程内起作用,它锁不住其他 worker 进程的内存空间。
正确做法必须换用进程间同步原语:
- 用
multiprocessing.Manager().dict()替代普通dict - 用
multiprocessing.Value或multiprocessing.Array替代数字/数组类全局变量 - 所有访问都通过 Manager 代理对象,不要直接操作原始类型
示例:共享一个计数器
from multiprocessing import Manager
<h1>启动时创建一次(通常放在 app 初始化阶段)</h1><p>manager = Manager()
shared_counter = manager.Value('i', 0) # 'i' 表示整型</p><p>@app.route('/inc')
def increment():
with shared_counter.get_lock(): # 注意:Value 自带 lock 方法
shared_counter.value += 1
return str(shared_counter.value)
</p>
Flask 的 g 对象不是全局变量,它只活在一个请求里
把数据塞进 g 然后指望多个请求能共享?不行。g 的生命周期严格绑定单次请求:@app.before_request 创建,响应发出后自动销毁。两次请求之间的 g 完全无关,哪怕同一个用户、同一浏览器发来两个请求。
如果你需要跨请求保存用户数据:
- 用
session(适合小数据、用户私有状态) - 用 Redis(适合高频读写、跨服务共享)
- 用数据库(适合需持久化、强一致性场景)
别试图用 g 模拟 session 或缓存——它设计上就不支持这个用途。
配置文件或模块常量可以,但不能被运行时修改
像 config.py 里的 DEBUG = True 或 API_TIMEOUT = 30 这类只读配置,完全可以作为“全局常量”使用。它们在应用启动时加载,各 worker 进程各自持有一份副本,只要不改,内容一致。
但一旦你尝试在运行时动态修改它(比如 config.API_TIMEOUT = 60),这个改动只影响当前 worker,其他 worker 仍用旧值。所以:
- 只读配置 → 安全可用
- 运行时可变状态 → 必须走外部存储(Redis / DB / Manager)
真正容易被忽略的是:很多人混淆了“配置”和“运行时状态”,以为改个模块变量就能热更新配置——在多 worker 部署下,这只会让行为变得不可预测。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











