在烧瓶应用中保持全局状态

Pro*_*sch 57 python state global flask

我试图在我的flask应用程序中保存缓存字典.

据我所知,应该使用Application Context,特别是flask.g对象.

建立:

import flask as f

app = f.Flask(__name__)
Run Code Online (Sandbox Code Playgroud)

如果我这样做:

with app.app_context():
    f.g.foo = "bar"
    print f.g.foo
Run Code Online (Sandbox Code Playgroud)

它打印bar.

继续以下内容:

with app.app_context():
    print f.g.foo

AttributeError: '_AppCtxGlobals' object has no attribute 'foo'
Run Code Online (Sandbox Code Playgroud)

我不明白,文档根本没有帮助.如果我正确阅读它们,应该保留状态.

我的另一个想法是简单地使用模块范围的变量:

cache = {}

def some_function():
    cache['foo'] = "bar"
Run Code Online (Sandbox Code Playgroud)

但似乎每次请求都会重置这些内容.

怎么做到这一点?

编辑: Flask 10.1

mal*_*vai 64

根据你的问题,我认为你对"全球"的定义感到困惑.

在Flask设置库中,您有一个Flask服务器,其中包含多个线程,并且可能有多个进程处理请求.假设您有一个像"itemlist = []"这样的股票全局变量,并且您希望在每个请求中继续添加它 - 比如每次有人向端点发出POST请求时.这在理论和实践中是完全可能的.这也是一个非常糟糕的主意.

问题是你无法轻易控制哪些线程和进程"赢" - 列表可能以一个非常糟糕的顺序出现,或者完全被破坏.所以现在你需要谈论锁,互斥和其他原语.这很难,也很烦人.

您应该将Web服务器本身保持为尽可能无状态.每个请求应该是完全独立的,不能在服务器中共享任何状态.相反,使用将为您处理状态的数据库或缓存层.这似乎更复杂,但实际上更简单.以SQLite为例; 这很简单.

要解决'flask.g'对象,这是一个基于每个请求的全局对象.

http://flask.pocoo.org/docs/api/#flask.g

它在请求之间"擦除",不能用于在它们之间共享状态.

  • 不得不-1这个答案.有些情况下,您希望在请求之间不刷新全局对象,例如,我想在内存中加载某些文件的路径,而不是**根本不修改它.如果我想修改它,我将重新启动服务器.这个答案没有帮助. (11认同)
  • 是的,我正在寻找一个大型的预训练模型进行推理,并且加载时间很长,因此不能成为无状态的。 (3认同)
  • 这不再是事实。从flask.10开始,flask.g绑定到应用程序上下文,而不是请求上下文。http://flask.pocoo.org/docs/0.12/api/#flask.g (2认同)
  • @CpILL 好运吗?相同的用例(除非您的模型是动态的?)。文档非常不连贯,并且关于该主题的大多数 SO 问题都被关闭为重复内容。 (2认同)

cod*_*eek 10

这条线

with app.app_context():
    f.g.foo = "bar"
Run Code Online (Sandbox Code Playgroud)

由于您使用的是"with"关键字,因此一旦执行此循环,它就会调用__exit__AppContext类的方法.看到这个.所以'foo'一旦完成就会弹出.这就是为什么你没有再次使用它.您可以尝试:

ctx = app.app_context()
f.g.foo = 'bar'
ctx.push()
Run Code Online (Sandbox Code Playgroud)

在您调用以下内容之前,g.foo应该可用

ctx.pop()
Run Code Online (Sandbox Code Playgroud)

我不知道你是否想要将它用于缓存目的.

  • 那我应该怎么用?我认为这是在应用程序中存储全局值的方法吗? (5认同)
  • 必要时创建并销毁应用程序上下文.它永远不会在线程之间移动,也不会在请求之间共享.(http://flask.pocoo.org/docs/appcontext/) (2认同)

Joh*_*Gov 8

我已经做了一些类似于我的"模块范围变量"的想法,我在烧瓶服务器中使用它来集成两个软件,我知道我将只有一个同时"用户"(作为发送者软件) .

我的app.py看起来像这样:

from flask import Flask
from flask.json import jsonify
app = Flask(__name__)

cache = {}

@app.route("/create")
def create():
    cache['foo'] = 0
    return jsonify(cache['foo'])

@app.route("/increment")
def increment():
    cache['foo'] = cache['foo'] + 1
    return jsonify(cache['foo'])

@app.route("/read")
def read():
    return jsonify(cache['foo'])

if __name__ == '__main__':
    app.run()
Run Code Online (Sandbox Code Playgroud)

你可以像这样测试它:

import requests

print(requests.get('http://127.0.0.1:5000/create').json())
print(requests.get('http://127.0.0.1:5000/increment').json())
print(requests.get('http://127.0.0.1:5000/increment').json())
print(requests.get('http://127.0.0.1:5000/read').json())
print(requests.get('http://127.0.0.1:5000/increment').json())
print(requests.get('http://127.0.0.1:5000/create').json())
print(requests.get('http://127.0.0.1:5000/read').json())
Run Code Online (Sandbox Code Playgroud)

输出:

0
1
2
2
3
0
0
Run Code Online (Sandbox Code Playgroud)

请谨慎使用,因为我希望这在不适当的多用户Web服务器环境中不起作用.

  • 这将适用于你有一个单一uwsgi工作者的情况.您还必须担心对变量的多次访问,因此您可能必须根据用途实现锁或类似操作.这是袋子里的另一个工具. (6认同)
  • 注意此类测试...测试Flask服务器是单线程的,并且是单个进程,因此您将无法在此测试中找到与多线程相关的问题。 (3认同)