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'))`
相關文章
相關標籤/搜索