Flask拾遗笔记之上下文

作者: 胡写八写 | 来源:发表于2017-07-16 12:15 被阅读45次

    0x01 背景知识

    threading.local()

    通过threading.local()可以创建一个线程安全的全局变量,即在一线程中的修改不会影响另一线程。结合代码说明:

    import threading
    storage = threading.local() # (1)
    storage.foo = 1
    print(storage.foo)
    class AnotherThread(threading.Thread):
         def run(self):
            # 这里的 storage和定义在(1)处的并非同一个,他们只是“名字一样”的两个变量
            storage.foo = 2
            print(storage.foo)
    another = AnotherThread()
    another.start()
    print(storage.foo)
    # 由于“并非”同一个变量,所以输出应该是
    1
    2
    1
    

    通过修改代码验证“名同实不同”:

    import threading
    storage = threading.local() # (1)
    storage.foo = 1
    print(storage.foo)
    class AnotherThread(threading.Thread):
         def run(self):
            # 运行会报错 '_thread._local' object has no attribute 'foo'
            # 从错误信息可以看出,这个线程里面的storage和(1)处的并非同一个
            print(storage.foo) 
    another = AnotherThread()
    another.start()
    print(storage.foo)
    

    所以threading.local()是通过创建“名同实不同”的“全局变量”。

    LocalProxy 和 LocalStack

    这两个都是基于 werkzeug.local.Local实现。

    werkzeug.local.Localthreading.local只有两个不同,一个是前者优先使用Greenlet的ID,其次是线程ID;二是前者实现了一个析构方法(__release_local__)来析构(删除)创建的werkzeug.local.Local对象。

    总的来说,前者是web升级版的threading.local. 那么顾名思义,LocalProxyLocalStack分别是线程安全的代理和线程安全的栈。

    0x02 上下文

    关于上下文,已经有很好的介绍文章了(见文末),我这里只做一些补充。

    线程不安全的情况

    在单App的情况下,通过current_app修改app配置会影响到其它线程。

    # 在这种情况下,第二个请求时的 secret_key 的值是'new'. 其它线程显然也会受到影响。
    
    from flask import Flask, current_app
    app = Flask(__name__)
    app.secret_key = 'key'
    
    @app.route('/')
    def foo():
        print(current_app.secret_key)
        current_app.secret_key = 'new'
    
    if __name__ == '__main__':
        app.run(threaded=True)
    ```
    
    ## 为什么要有LocalProxy
    
    按前文所述,通过``` LocalProxy ```拿到的是一个“名同实不同”的变量。例如``` flask ```中的``` request ```, 他就是一个``` LocalProxy ```对象,我们经常需要通过这个变量拿到一些请求参数。这时,将其变成“名同实不同"的全局变量,显然要比在每个视图函数中都传入一个``` request ```参数来得方便。
    
    ## 为什么要有LocalStack
    按前文所述,通过``` LocalProxy ```存储的是“名同实不同”的变量。我们已经知道这种“名同实不同”的变量会让我们在不同线程中方便地使用同一名称的变量,但是如果一个线程中有多个变量呢?
    
    > 只有栈结构才能保存多个 Context 并在其中定位出哪个才是“当前”。
    
    在作为一个简单的网站后台时,一般不会有这种情况,因为一个HTTP请求对于一个request 环境和一个 application 环境。但是,在离线测试的时候,可能会推入栈中多个context。
    
    ----
    相关好文
    
    >Flask 的 Context 机制 —— Jiangge Zhang
     https://blog.tonyseek.com/post/the-context-mechanism-of-flask/
    >flask 源码解析:上下文 ——  [**cizixs**](https://segmentfault.com/u/cizixs)
    https://segmentfault.com/a/1190000008383197

    相关文章

      网友评论

        本文标题:Flask拾遗笔记之上下文

        本文链接:https://www.haomeiwen.com/subject/jwstkxtx.html