• flask上下文管理


    一、flask的上下文管理

        与threading.local实现方式相同,创建一个字典{线程或协程唯一标识:要存的数据},保证了数据的隔离;

           而django/tornado框架是通过传参的形式实现的。

         (1)请求上下文流程  

    • 代码启动时,先对LocalStack、Local、LocalProxy三个类初始化
    • 请求进来时:将请求的相关数据封装到了RequestContext中,通过LocalStack将对象添加到Local类中(每个线程协程独立空间存储),     
    _request_ctx_stack.local = {
                        唯一标识:{
                            "stack":[ctx, ]
                        },
                    }

    # ctx.app # 当前APP的名称
    # ctx.request # Request对象(封装请求相关东西)
    # ctx.session # 空

    • 使用request:  如,print(request)会调用LocalProxy中的__str__方法,request.method会调用LocalProxy中的__getattr方法等,调用这些

              方法就相当于执行了偏函数_lookup_req_object,通过LocalStack去Local中获取值(ctx)

    • 请求终止:通过LocalStack中的pop方法将Local类中属于该请求的数据删除掉

      (2)应用上下文流程(0.9版本之后才有的):就是为了将一个请求周期需要传递的值与request分开,

      其与请求上下文流程相同,就是创建了LocalProxy类的新对象g=LocalProxy(partial(_lookup_app_object, 'g'))

    •  代码启动时,需要对类LocalStack、Local、LocalProxy初始化
    •   当请求到来时,也会将要传递的值封装到RequestContext中,通过LocalStack将对象添加到Local类中(每个线程协程独立空间存储),
    _app_ctx_stack.local = {
                        唯一标识:{
                            "stack":[app_ctx, ]
                        },
                        唯一标识:{
                            "stack":[app_ctx, ]
                        },
                    }
    
    #app_ctx=AppContext对象
    #app_ctx.app:该app对象
    #app_ctx.g:每个请求周期都会创建一个用于在请求周期中传递值的一个容器
    • 使用,也会调用LocalProxy中对应方法,从而执行偏函数_lookup_app_object,通过LocalStack类从Local类中获取值(app_ctx)
    • 请求终止时,通过LocalStack中的pop方法将Local类中属于该线程或协程的数据清除掉

    二、flask上下文管理相关问题

    • 多线程或协程如何实现
    _request_ctx_stack.local = {
                        唯一标识1:{
                            "stack":[ctx, ]
                        },
                        唯一标识2:{
                            "stack":[ctx, ]
                        },
                     ......多少个线程或协程,就有多少个唯一标识
                    }
    
    _app_ctx_stack.local = {
                        唯一标识1:{
                            "stack":[app_ctx, ]
                        },
                        唯一标识2:{
                            "stack":[app_ctx, ]
                        },
                    ......多少个线程或协程,就有多少个唯一标识                              
                    }    
    • flask的local保存数据时,使用了列表创建出栈,为什么使用了栈

              (1)写web程序,web运行环境;栈中永远保存一条数据,可以不用栈

              (2)写脚本获取app信息时,可能存在app上下文嵌套关系,栈中会有多条数据,往出取的时候也是取的自己的数据(测试会用)

    from flask import Flask,request,current_app,_app_ctx_stack
    
    app1=Flask('app01')
    app1.debug=False
    
    
    app2=Flask('app02')
    app2.debug=True
    
    
    with app1.app_context():  #__enter__方法-->push-->app_ctx添加到_app_ctx_stack.local
        print(_app_ctx_stack._local.__storage__)
        print(current_app.config['DEBUG'])
    
        with app2.app_context():  # __enter__方法-->push-->app_ctx添加到_app_ctx_stack.local
            print(_app_ctx_stack._local.__storage__)
            print(current_app.config['DEBUG'])

               (3)Web访问多app应用时,上下文管理是如何实现?

      •   多app应用:在找到路由之前分发好路由,是通过字符串分隔实现,而蓝图是找到路由之后再分发路由
    from werkzeug.wsgi import DispatcherMiddleware
    from werkzeug.serving import run_simple
    from flask import Flask
    
    app1=Flask('app01')
    app2=Flask('app02')
    
    @app1.route('/index')
    def index():
        return 'index'
    
    @app2.route('/index2')
    def index2():
        return 'index2'
    
    # http://localhost:5000/index
    # http://localhost:5000/sec/index2
    dm=DispatcherMiddleware(app1,{
        '/sec':app2,
    })

    if __name__ == "__main__":
    app2.__call__
    run_simple('localhost', 5000, dm)
      • 上下文管理是如何实现

          run_simple('localhost', 5000, dm) 会执行DispatcherMiddleware类的__call__方法

        def __call__(self, environ, start_response):
            script = environ.get('PATH_INFO', '')
            path_info = ''
            while '/' in script:
                if script in self.mounts:
                    app = self.mounts[script]
                    break
                script, last_item = script.rsplit('/', 1)
                path_info = '/%s%s' % (last_item, path_info)
            else:
                app = self.mounts.get(script, self.app)
            original_script_name = environ.get('SCRIPT_NAME', '')
            environ['SCRIPT_NAME'] = original_script_name + script
            environ['PATH_INFO'] = path_info
            return app(environ, start_response)

    返回app(environ,start_response),又调用Flask类的__call__方法

  • 相关阅读:
    Median Value
    237. Delete Node in a Linked List
    206. Reverse Linked List
    160. Intersection of Two Linked Lists
    83. Remove Duplicates from Sorted List
    21. Merge Two Sorted Lists
    477. Total Hamming Distance
    421. Maximum XOR of Two Numbers in an Array
    397. Integer Replacement
    318. Maximum Product of Word Lengths
  • 原文地址:https://www.cnblogs.com/meng0410/p/8659276.html
Copyright © 2020-2023  润新知