在我的应用程序中,通过发出请求更改公共对象的状态,并且响应取决于状态。
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的唯一数字。或者会发生这样的事情:
self.param
递增1。self.param
再次递增。由于只有两个客户,预期结果是1和2,而不是2和3。跳过了一个数字。
当我扩展应用程序时,这真的会发生吗?除了全局变量,我还应该考虑哪些替代方案?
不能使用全局变量保存此类数据。它不仅不是线程安全的,也不是进程安全的,生产中的WSGI服务器会产生多个进程。如果您使用线程处理请求,那么您的计数不仅是错误的,而且还会根据处理请求的进程而有所不同。
使用烧瓶外的数据源保存全局数据。根据您的需要,数据库、memcached或redis都是适当的独立存储区域。如果需要加载和访问Python数据,请考虑^{} 。您还可以将会话用于每个用户的简单数据。
开发服务器可以在单线程和进程中运行。您将看不到所描述的行为,因为每个请求都将同步处理。启用线程或进程,您将看到它。
app.run(threaded=True)
或app.run(processes=10)
。(在1.0中,默认情况下服务器是线程化的。)一些WSGI服务器可能支持gevent或其他异步工作器。全局变量仍然不是线程安全的,因为仍然没有针对大多数竞争条件的保护。你仍然可以有这样一个场景:一个工人得到一个值,产生,另一个工人修改它,产生,然后第一个工人也修改它。
如果在请求期间需要存储一些全局数据,可以使用Flask的^{} object 。另一个常见的情况是一些管理数据库连接的顶级对象。这种类型的“全局”的区别在于它对每个请求都是唯一的,而不是在请求之间使用,并且有一些东西管理资源的设置和拆卸。
这并不是解决全局线程安全问题的真正方法。
但我认为在这里提到会议很重要。 您正在寻找存储客户机特定数据的方法。每个连接都应该以线程安全的方式访问自己的数据池。
这在服务器端会话中是可能的,它们可以在一个非常整洁的flask插件中使用:https://pythonhosted.org/Flask-Session/
如果您设置了会话,那么在所有路由中都有一个
session
变量,它的行为就像一个字典。此字典中存储的数据对于每个连接的客户端都是独立的。下面是一个简短的演示:
在
pip install Flask-Session
之后,您应该能够运行这个。尝试从不同的浏览器访问它,您将看到计数器在它们之间不共享。相关问题 更多 >
编程相关推荐