python - Flask 中的全局变量是线程安全的吗?如何在请求之间共享数据?

标签 python flask thread-safety

在我的应用程序中,一个普通对象的状态是通过发出请求来改变的,响应取决于状态。

class SomeObj():
    def __init__(self, param):
        self.param = param
    def query(self):
        self.param += 1
        return self.param

global_obj = SomeObj(0)

@app.route('/')
def home():
    flash(global_obj.query())
    render_template('index.html')

如果我在我的开发服务器上运行它,我希望得到 1、2、3 等等。如果同时从 100 个不同的客户端发出请求,会出现问题吗?预期的结果是 100 个不同的客户端每个都看到一个从 1 到 100 的唯一数字。或者会发生这样的事情:

  1. 客户端 1 查询。 self.param 加 1。
  2. 在return语句执行之前,线程切换到客户端2。self.param再次递增。
  3. 线程切换回客户端 1,客户端返回数字 2。
  4. 现在线程移动到客户端 2 并返回他/她的数字 3。

由于只有两个客户端,因此预期结果是 1 和 2,而不是 2 和 3。跳过了一个数字。

当我扩展我的应用程序时,这真的会发生吗?我应该看看全局变量的哪些替代方案?

最佳答案

您不能使用全局变量来保存此类数据。它不仅不是线程安全的,也不是进程安全的,而且生产环境中的 WSGI 服务器会产生多个进程。如果您使用线程来处理请求,您的计数不仅会出错,而且还会根据处理请求的进程而有所不同。

使用 Flask 之外的数据源来保存全局数据。数据库、memcached 或 redis 都是合适的单独存储区域,具体取决于您的需要。如果您需要加载和访问 Python 数据,请考虑 multiprocessing.Manager .您还可以将 session 用于每个用户的简单数据。


开发服务器可以在单线程和进程中运行。您不会看到您描述的行为,因为每个请求都将被同步处理。启用线程或进程,您将看到它。 app.run(threaded=True)app.run(processes=10)。 (在 1.0 中,服务器默认是线程化的。)


一些 WSGI 服务器可能支持 gevent 或其他异步 worker 。全局变量仍然不是线程安全的,因为仍然没有针对大多数竞争条件的保护。你仍然可以有这样的场景,一个 worker 得到一个值,产出,另一个修改它,产出,然后第一个 worker 也修改它。


如果您需要在请求期间存储一些全局数据,您可以使用 Flask 的 g object .另一个常见的情况是一些管理数据库连接的顶级对象。这种“全局”类型的区别在于它对每个请求都是唯一的,而不是在个请求之间使用,并且有一些东西可以管理资源的设置和拆卸。

关于python - Flask 中的全局变量是线程安全的吗?如何在请求之间共享数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32815451/

相关文章:

python - Pandas 查找不连续数据的方法

python - 数据库错误 : Write pandas dataframe to vertica using to_sql and vertica_python

python - Dockerfile 入口点问题

python - 无法在 websockets 事件的事件处理程序中修改 session 的值

java - 抽象 Servlet - 这个方法是线程安全的吗?

sql - Android的SQLiteStatement(准备好的语句)是线程安全的吗? IE。 "bind*, bind*... execute"是原子的吗?

python - 创建多维零点 Python

python - 如何从字符串表示形式创建 ObjectID [pyarrow]

python - 保护 Flask 上的 POST 请求

c++ - 我如何使用比系统提供的更新版本的 clang 链接到线程清理器?