flask 请求上下文

一篇引用大牛的
https://www.cnblogs.com/zhaopanpan/p/9457343.html
### 线程安全  ```python# 线程不安全class Foo(object):    passfoo = Foo()foo.num = 1import timeimport threadingdef my_num(i):    foo.num = i    time.sleep(1)    print(foo.num,threading.current_thread().ident)for i in range(20):    th = threading.Thread(target=my_num,args=(i,))    th.start()----------------------------------------------------------------------------# 线程安全from threading import localclass Foo(local):    passfoo = Foo()foo.num = 1import timeimport threadingdef my_num(i):    foo.num = i    time.sleep(1)    print(foo.num,threading.current_thread().ident)for i in range(200000):    th = threading.Thread(target=my_num,args=(i,))    th.start()# 开辟新空间 - 浪费了部分资源 - 速度保证 - 保证安全"""{    16232:[request],# 123    17164:[request],# 456    9088: [request],# 567    16084:[request],# 789}Threading.localFlask 上下文机制就是使用的 Threading.local线程进来 开辟一个空间给这个线程,线程操做的全部任务,都会复制一份儿到空间中"""```### 栈  Stack```python# Stackclass MyStack(object):    data = []    def __setattr__(self, key, value):        self.push(key,value)    def push(self,key,value):        self.data.append({key:value})    def top(self):        return self.data.pop()my_stack = MyStack()my_stack.name = 666 # [{name:666}]my_stack.name = 777 # [{name:666},{name:777}]print(my_stack.data)# my_stack.push(666)# my_stack.push(777)# my_stack.push(888)## print(my_stack.top(),my_stack.data)# print(my_stack.top(),my_stack.data)# print(my_stack.top(),my_stack.data)```### 局部的栈 LocalStack ```python# LocalStack  安全的 栈from threading import get_ident  # 获取当前线程的 idimport threadingclass MyLocalStack(object):    storage={}    def push(self,item):        try:            self.storage[get_ident()].append(item)        except:            self.storage[get_ident()]=[item]    def top(self):        return self.storage[get_ident()].pop()my_local_stack = MyLocalStack()import timedef go(i):    my_local_stack.push(i)    time.sleep(1)    # my_local_stack.top()for i in range(5):    th = threading.Thread(target=go,args=(i,))    th.start()print(my_local_stack.storage)```## flask 的 请求上下文+ ## werkzeug   + flask 的 wsgi ```pythonfrom werkzeug.wrappers import Request,Responsefrom werkzeug.serving import run_simple@Request.applicationdef app(environ):    print(environ)    return Response("200OK")run_simple("0.0.0.0",9527,app)  ``````pythonfrom flask import Flaskapp = Flask(__name__)if __name__ == '__main__':    app.run(host='0.0.0.0',port=7088)       app.__call__    app.wsgi_app```### 上文1. 从 **`run()`** 开始   + 进入源码  其中的  >> `self = app = Flask()`     + 导入了 `from werkzeug.serving import run_simple`  执行了  `run_simple(host, port, self, **options)` 方法        + 看这一句   `run_simple("0.0.0.0",9527, app) ` 也就是说      self  会执行  >> `self = app = Flask() = self()`      + 也就 == app()  对象()  执行 类的  `__call__()` 方法     2. `__call__() ` 执行了 `self.wsgi_app(environ, start_redponse)`    **environ  =  request 原始信息**   3. 进入 `app.wsgi_app`    +  `def wsgi_app(self, environ, start_response):` >> self = app = Flask()   +  self 执行了这个方法 `ctx = self.request_context(environ)`  方法中执行了 一个类 `RequestContext(self, environ)` ctx.py文件中  >>  这个对象中 包含了 两个 值  requset/session     ctx = requsetcontext -->  requset/session    + 在这个类中 的 初始化方法 中  `def __init__(self, app, environ, request=None):`  >>  self  = RequestContext  ->request/session     app = Flask    request=None    执行方法  `request = app.request_class(environ)` 这个方法将 environ  序列化 出了 request对象  就是能够使用  request.method  requset.form ...  方法  了     + 执行ctx.push() 方法  4. ctx.push() 方法         + 方法中执行了  `top = _request_ctx_stack.top`   --> `_request_ctx_stack = LocalStack()`   实例化时的  `__init__` 方法中 初始化了  两个 对象 >>  `self._local = {"__storage__": {}, "__ident_func__": get_ident}`       >`get_ident` 获取线程 或携程的 id  并无执行       + `_request_ctx_stack = {"__storage__": {}, "__ident_func__": get_ident}`   + `.top ` 方法  执行了  `self._local.stact[-1]`    .stack 调用 Local(object):  对象的 `__getattr__(self) 方法`       + 方法中  调用  `self.__storage__[self.__ident_func__()][name]`  也就是从        `{"__storage__": {}, "__ident_func__": get_ident}` 中的  `__storage__` 中经过key 取值 此时 `__storage__` 中为 空字典  报错  抛出异常  `AttributeError(name)`  这个异常在上面的  top 方法中 被捕获 返回 一个 None     返回 **top = None**    以后的 if 判断不成立     + 以后又执行了  `_request_ctx_stack.push(self)` 代码  其中的   ` _request_ctx_stack = {"__storage__": {}, "__ident_func__": get_ident}`     + 执行了.push(self) 方法   这个self = ctx = requset/session   进入 push() 方法   + `def push(self, obj)`这里面的  self 是 ` _request_ctx_stack = {"__storage__": {}, "__ident_func__": get_ident}`    obj =  ctx = requset/session    执行 :  ` rv = getattr(self._local, 'stack', None)`  `self._local = {"__storage__": {}, "__ident_func__": get_ident}`  rv = None  -> if判断 执行` self._local.stack = rv = [] rv.append(obj) `    走对象的  `__setattr__(self,name,value)`方法   返回 =>>  `{"__storage__": {7088:{"stack": rv=[] }}, "__ident_func__": get_ident}`     + 返回 rv.append(obj)  ==>`{"__storage__": {7088:{"stack": [ctx=>request/session] }}, "__ident_func__": get_ident}`    `rv=[ctx=>request/session]  `  并无接收返回值  执行完以后  `self._local = {"__storage__": {7088:{"stack": [ctx=>request/session] }}, "__ident_func__": get_ident}`      ### 下文      + 使用时才执行       ```python     @app.route("/")     def login():         if requset.method =='POST':             ...             # requset.method 以后启动下文     ```   +  进入 request       ```python     # partial 偏函数     request = LocalProxy(         partial(             _lookup_req_object,              'request'         )     )     ```   + `_lookup_req_object`       ```python     def _lookup_req_object(name):         top = _request_ctx_stack.top         # _request_ctx_stack = self._local = {"__storage__": {7088:{"stack": [ctx=>request/session] }}, "__ident_func__": get_ident}  调用.top 方法         if top is None:             raise RuntimeError(_request_ctx_err_msg)         return getattr(top, name)     ```   + .top    中 执行了  `self._local.stack[-1]`     ```python     # 执行 self._local的 __getattr__ 方法       def __getattr__(self, name):         try:             return self.__storage__[self.__ident_func__()][name]         except KeyError:             raise AttributeError(name)                  # 返回了  [ctx => request / session ]       ```     执行 [-1]  获得 `ctx => request / session`   + `top = ctx => request / session`     + `getattr(top, name)`  name = request   从偏函数传递过来的  方法 获得了 一个 request 对象  及 request 的真身   + 查看` LocalProxy(偏函数没被执行的 )`   实例化  执行`def __init__(self, local, name=None):`   local  = request 的偏函数       ```python     def __init__(self, local, name=None):         object.__setattr__(self, '_LocalProxy__local', local)         object.__setattr__(self, '__name__', name)         if callable(local) and not hasattr(local, '__release_local__'):             # "local" is a callable that is not an instance of Local or             # LocalManager: mark it as a wrapped function.             object.__setattr__(self, '__wrapped__', local)     ```   + request.method 执行  .方法 调用  `__getattr__()`    执行 `getattr(self._get_current_object(), name)`        ```python     def _get_current_object(self):         if not hasattr(self.__local, '__release_local__'):             return self.__local()         try:             return getattr(self.__local, self.__name__)         except AttributeError:             raise RuntimeError('no object bound to %s' % self.__name__)     ```     `__local = local = requset偏函数执行  = requset`    + `getattr(request, name)`    name = method   + ### 查看 LocalProxy  类  包含了 全部面向对象的  特殊方法### 应用上下文+ 会在 离线脚本 的时候使用+ 从  `app.wsgi_app`  中 找到   `ctx.push()` 的方法 + `app_ctx = _app_ctx_stack.top` 这个  就是应用上下文  ```python  app_ctx = _app_ctx_stack.top  if app_ctx is None or app_ctx.app != self.app:      app_ctx = self.app.app_context()      app_ctx.push()      self._implicit_app_ctx_stack.append(app_ctx)      else:          self._implicit_app_ctx_stack.append(None)  ```    1. `_app_ctx_stack  = {"__storage__": {}, "__ident_func__": get_ident}`  2. `.top` 方法 返回的仍是  None    3. `app_ctx = None`+  `app_ctx = self.app.app_context()`  序列化 app  获得  AppContext(app,g) -> requestcontext(request/session)  +  `app_ctx.push()`   获得 `self._local = {"__storage__": {7088:{"stack": [app_ctx(app, g)] }}, "__ident_func__": get_ident}`  g会在 离线脚本 的时候使用 `current_app = LocalProxy(_find_app)` = app = Flask()```pythondef _find_app():    top = _app_ctx_stack.top  # 拿到 app_ctx(app,g)    if top is None:        raise RuntimeError(_app_ctx_err_msg)    return top.app  # 返回一个 app  独立的 app ```请求结束以后执行 pop 方法  删除缓存`g = LocalProxy(partial(_lookup_app_object, 'g'))`
相关文章
相关标签/搜索