一篇引用大牛的 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'))`