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

在我的应用程序中,公共对象的状态通过发出请求而改变,响应取决于状态

类SomeObj():
定义初始化(self,param):
self.param=param
def查询(自我):
self.param+=1
返回self.param
全局对象=某些对象(0)
@应用程序路径(“/”)
def home():
闪存(全局对象查询())
呈现模板('index.html')

如果我在我的开发服务器上运行这个,我希望得到1、2、3等等。如果同时从100个不同的客户端发出请求,是否会出现问题?预期的结果是,100个不同的客户端都会看到一个从1到100的唯一数字。还是会发生类似的事情:

  1. 客户端1查询self.param递增1
  2. 在执行return语句之前,线程将切换到客户机2自身参数再次递增
  3. 线程切换回客户端1,客户端返回数字2,比如说
  4. 现在,线程移动到客户机2,并将数字3返回给他/她

因为只有两个客户,所以预期结果是1和2,而不是2和3。跳过了一个数字

当我扩展我的应用程序时,这真的会发生吗?我应该考虑哪些全局变量的替代方案

不能使用全局变量保存此类数据。它不仅不是线程安全的,也不是进程安全的,而且生产中的WSGI服务器会产生多个进程。如果您使用线程来处理请求,那么您的计数不仅会出错,而且还会因处理请求的进程而异

使用烧瓶外部的数据源保存全局数据。数据库、memcached或redis都是适当的单独存储区域,具体取决于您的需要。如果需要加载和访问Python数据,请考虑 MultualPurtual.Manager 。您还可以将会话用于每个用户的简单数据


开发服务器可以在单线程和进程中运行。您将看不到所描述的行为,因为每个请求都将被同步处理。启用线程或进程,您将看到它应用程序运行(threaded=True)或应用程序运行(processs=10)。(在1.0中,服务器默认为线程化。)


一些WSGI服务器可能支持gevent或其他异步工作程序。全局变量仍然不是线程安全的,因为仍然没有针对大多数竞争条件的保护。您仍然可以有这样一个场景:一个工人获得一个值,产生,另一个工人修改它,产生,然后第一个工人也修改它


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

发表评论