在我的应用程序中,通过发出请求来更改公共(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 查询。
self.param
增加 1。 - 在执行 return 语句之前,线程切换到客户端 2。
self.param
再次递增。 - 线程切换回客户端 1,并且客户端返回数字 2。
- 现在线程移动到客户端 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/