Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/353.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 全局变量在烧瓶中是线程安全的吗?如何在请求之间共享数据?_Python_Flask_Thread Safety - Fatal编程技术网

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

Python 全局变量在烧瓶中是线程安全的吗?如何在请求之间共享数据?,python,flask,thread-safety,Python,Flask,Thread Safety,在我的应用程序中,公共对象的状态通过发出请求而改变,响应取决于状态 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

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

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<代码>自身参数再次递增
  • 线程切换回客户端1,客户端返回数字2,比如说
  • 现在,线程移动到客户机2,并将数字3返回给他/她
  • 因为只有两个客户,所以预期结果是1和2,而不是2和3。跳过了一个数字


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

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

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


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


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



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

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

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


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


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



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

    这并不是对全局线程安全的真正回答

    但我认为在这里提到会议是很重要的。 您正在寻找一种存储特定于客户端的数据的方法。每个连接都应该以线程安全的方式访问自己的数据池

    这在服务器端会话中是可能的,它们可以在一个非常整洁的flask插件中使用:

    如果设置会话,则所有路由中都有一个
    session
    变量,其行为类似于字典。对于每个连接的客户端,此字典中存储的数据是单独的

    下面是一个简短的演示:

    from flask import Flask, session
    from flask_session import Session
    
    app = Flask(__name__)
    # Check Configuration section for more details
    SESSION_TYPE = 'filesystem'
    app.config.from_object(__name__)
    Session(app)
    
    @app.route('/')
    def reset():
        session["counter"]=0
    
        return "counter was reset"
    
    @app.route('/inc')
    def routeA():
        if not "counter" in session:
            session["counter"]=0
    
        session["counter"]+=1
    
        return "counter is {}".format(session["counter"])
    
    @app.route('/dec')
    def routeB():
        if not "counter" in session:
            session["counter"] = 0
    
        session["counter"] -= 1
    
        return "counter is {}".format(session["counter"])
    
    
    if __name__ == '__main__':
        app.run()
    

    pip安装Flask会话之后
    ,您应该能够运行此操作。尝试从不同的浏览器访问它,你会发现计数器不是在它们之间共享的。

    这并不是对全局线程安全的真正回答

    但我认为在这里提到会议是很重要的。 您正在寻找一种存储特定于客户端的数据的方法。每个连接都应该以线程安全的方式访问自己的数据池

    这在服务器端会话中是可能的,它们可以在一个非常整洁的flask插件中使用:

    如果设置会话,则所有路由中都有一个
    session
    变量,其行为类似于字典。对于每个连接的客户端,此字典中存储的数据是单独的

    下面是一个简短的演示:

    from flask import Flask, session
    from flask_session import Session
    
    app = Flask(__name__)
    # Check Configuration section for more details
    SESSION_TYPE = 'filesystem'
    app.config.from_object(__name__)
    Session(app)
    
    @app.route('/')
    def reset():
        session["counter"]=0
    
        return "counter was reset"
    
    @app.route('/inc')
    def routeA():
        if not "counter" in session:
            session["counter"]=0
    
        session["counter"]+=1
    
        return "counter is {}".format(session["counter"])
    
    @app.route('/dec')
    def routeB():
        if not "counter" in session:
            session["counter"] = 0
    
        session["counter"] -= 1
    
        return "counter is {}".format(session["counter"])
    
    
    if __name__ == '__main__':
        app.run()
    

    pip安装Flask会话之后
    ,您应该能够运行此操作。尝试从不同的浏览器访问它,你会发现计数器不是在他们之间共享的。

    同时完全接受先前的上浮答案,并且不鼓励使用gl
    # Import cache
    from common import cache
    
    # ...
    app = Flask(__name__)
    
    cache.init_app(app=app, config={"CACHE_TYPE": "filesystem",'CACHE_DIR': Path('/tmp')})