You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flask中对象修改仅在请求上下文内生效的问题及解决咨询

问题描述

在大型多线程Flask应用中遇到异常现象:路由函数内修改模块级对象的属性时,仅在路由上下文内生效,外部访问该对象时属性仍为修改前的值。以下是复现代码:

项目结构

app/
├── __init__.py
└── routes.py
runserv.py

app/init.py

from flask import Flask

class NumberStore:
    def __init__(self):
        self.number = 1

    def set_number(self, number):
        self.number = number

app = Flask(__name__)
numberstore = NumberStore()

from app import routes

app/routes.py

from app import app, numberstore

@app.route('/get')
def get():
    return f"The number holder has id {id(numberstore)} and the number is {numberstore.number}"

@app.route('/set')
def set():
    numberstore.set_number(2)
    return f"The number holder has id {id(numberstore)} and the number has been set to {numberstore.number}"

runserv.py

import requests
from multiprocessing import Process

from app import app, numberstore

s = Process(target=lambda : app.run())
s.start()

交互测试结果

laptop:~/testserver$ python3 -i runserv.py 
 * Serving Flask app 'app'
 * Debug mode: off
>>> WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit

>>> numberstore.number
1
>>> id(numberstore)
139855264957008
>>> print(requests.get("http://127.0.0.1:5000/get").text)
The number holder has id 139855264957008 and the number is 1
>>> print(requests.get("http://127.0.0.1:5000/set").text)
The number holder has id 139855264957008 and the number has been set to 2
>>> numberstore.number
1
>>> print(requests.get("http://127.0.0.1:5000/get").text)
The number holder has id 139855264957008 and the number is 2
>>> numberstore.set_number(3)
>>> numberstore.number
3
>>> print(requests.get("http://127.0.0.1:5000/get").text)
The number holder has id 139855264957008 and the number is 2

疑问

  1. Flask为何会有这种机制?
  2. 能否规避该机制?
  3. 需要在路由端点函数中修改模块级对象的属性并让外部同步生效,是否可行?

解答

1. 原因:进程隔离而非Flask特性

这不是Flask的机制,而是多进程的内存隔离特性导致的。你用multiprocessing.Process启动Flask开发服务器时,主进程(交互式会话)和子进程(Flask服务器)是完全独立的进程,各自拥有独立的内存空间:

  • 子进程启动时会复制父进程的numberstore对象到自身内存,两个进程的numberstore是不同实例;Python的对象ID仅在单个进程内唯一,所以会出现ID一致但实际是两个对象的情况。
  • 路由函数修改的是子进程内的numberstore,主进程的实例不受影响;反之,主进程手动修改的也是自身内存里的实例,子进程的实例不会同步。

2. 规避方案

要实现状态同步,需要打破进程内存隔离,常见方案:

  • 单进程运行Flask:直接在交互式会话中调用app.run(),不使用multiprocessing.Process,所有操作在同一进程内,修改会全局生效。
  • 使用进程间通信(IPC):通过multiprocessing.Queue、Pipe或共享内存(multiprocessing.Value/Array)同步数据;也可以用外部存储(如Redis、数据库)作为中间层,让主进程和子进程通过访问外部存储共享状态。

3. 是否可行:取决于运行模式

  • 单进程模式:完全可行,模块级对象的修改会全局生效,路由内外访问的是同一个实例。
  • 多进程模式:直接修改模块级对象无法跨进程同步,必须借助IPC或外部共享存储传递状态。

内容的提问来源于stack exchange,提问作者kid-c-plus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 21:34:59