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

标签 python flask thread-safety

在我的应用程序中,通过发出请求来更改公共(public)对象的状态,并且响应取决于状态。

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 或其他异步工作线程。全局变量仍然不是线程安全的,因为仍然没有针对大多数竞争条件的保护。您仍然可以遇到这样的情况:一个工作人员获取一个值,产生结果,另一个工作人员修改它,产生结果,然后第一个工作人员也修改它。

<小时/>

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

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

相关文章:

c++ - 在终端中更智能地查看程序输出 - 显示/隐藏较低优先级输出的按钮,允许向下钻取程序输出

python - 手动计算 AUC,无需使用任何 Numpy 或 Sklearn 库

java - 为什么Java中的非线程安全计数器总是返回正确的值?

c# - 从多个线程访问这个变量是否安全?

java - 设置 HashMap 线程安全吗?

python - `pd.concat` 与 `join==' 内部 '` 不会产生 Pandas 数据帧的交集

python - load_entry_point 看不到其他模块 - "No module named"错误

python - SqlAlchemy 如何更新所有行的一列数据?

python - 无法使用 docker-compose 连接到 MongoDB

python-2.7 - 如何将值传递给可插入 View ?