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. 在执行返回语句之前,线程切换到客户端 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 。全局变量仍然不是线程安全的,因为仍然没有针对大多数竞争条件的保护。您仍然可以有一个场景,其中一个工作人员获取一个值,产生,另一个工作人员修改它,产生,然后第一个工作人员也修改它。


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

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

相关文章:

python - 部分函数 "officially"是否可以pickl?

vue.js - 此 set-cookie 被阻止,因为它具有 samesite=lax

python - 多重索引切片无法按预期工作(涉及词法排序元组的错误)

python - 避免在实例变量定义中执行

python - 在 Flask-Login 上禁用从多个不同位置同时登录

python - 使用 sphinx 记录 flask 应用程序

python - 如何在 Flask sqlalchemy 中查询某段日期时间?

java - Collections.synchronizedMap(new LinkedHashMap());没有使 Map 线程安全

java - Java Spring Bean 中的实例变量

java - "delegation"如何帮助线程安全类?