在我的应用程序中,一个普通对象的状态是通过发出请求来改变的,响应取决于状态。
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 或其他异步 worker 。全局变量仍然不是线程安全的,因为仍然没有针对大多数竞争条件的保护。你仍然可以有这样的场景,一个 worker 得到一个值,产出,另一个修改它,产出,然后第一个 worker 也修改它。
如果您需要在请求期间存储一些全局数据,您可以使用 Flask 的 g
object .另一个常见的情况是一些管理数据库连接的顶级对象。这种“全局”类型的区别在于它对每个请求都是唯一的,而不是在在个请求之间使用,并且有一些东西可以管理资源的设置和拆卸。
关于python - Flask 中的全局变量是线程安全的吗?如何在请求之间共享数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32815451/