Flask session,request,current_app的傳遞
請求上下文的作用 -- 封裝請求相關得數據(request,session)
請求上下文
request
session
request local類 {線程,協程的唯一ID:{stack:[RequestContext(request,session)]}}
應用上下文
app local類 {線程,協程的唯一ID:{stack:[AppContext(app,g)]}}
# app 保存着 應用相關的值
# g 每次請求周期都會創建一個用於在請求周期中傳遞值 的 容器
1 flask的 request, session 和 current_app 都是 設置方式比較新穎 -- 通過上下文管理的方式實現的
類似於本地線程 threading_local ,創建Local類
local = {
'線程或者協程的唯一標識':{'stack':[RequestContext(),]}, # a 每個線程一份
'線程或者協程的唯一標識':{'stack':[RequestContext(),]}, # b
'線程或者協程的唯一標識':{'stack':[RequestContext(),]}, # c
'線程或者協程的唯一標識':{'stack':[RequestContext(),]}, # d
'線程或者協程的唯一標識':{'stack':[RequestContext(),]}, # e
}
每次請求進來app.run調用 call 方法, 將包含了所有請求相關數據的實例對象RequestContext()添加, 通過stack(鍵),push到一個地方Local中,使用的時候再去取(top方法取值),在請求結束后返回的時候 pop 掉
與Django的區別
請求相關數據的傳遞方式 :
Django
參數一個一個傳遞
Flask
基於Local(類似於本地線程)和LocalStack(push, pop, top)完成
參數不用來回傳遞, 直接獲取reqeust
多個請求一起數據也不會混淆
單線程 - - 每次只能有一個請求處理
多線程 - - 通過Local實現不同的數據划分 - - thread - -線程的唯一標識
協程 - - greenlet - - 協程的唯一標識
flask 的上下文管理機制描述
(1) 與django相比是兩種不同的方式實現:
django/tornado 是通過傳參的方式
flask 第通過上下文管理機制
兩種都可以實現,只是實現的方式不一樣
(2)類似 threading local 機制,
flask創建 一個local類 {線程,協程的唯一ID:{stack:[RequestContext(request,session)]}} 保證數據隔離
請求進來 把ReqeustContext對象 push到 對應的stack中
使用 的時候 通過localstack的top方法,獲取local中的reqeust
請求終止 通過localstack pop方法,刪除local的request
2 補充 partial 函數
其實就是函數調用的時候,有多個參數 參數,但是其中的一個參數已經知道了,我們可以通過這個參數重新綁定一個新的函數,然后去調用這個新函數。
from functools import partial
def f(a,b):
return a + b
f1 = partial(f,10)
print(f1(5))
-->> 15
3 唯一標識
基於 Local類
類似於本地線程theading_local -->> 每一個線程 創建一個
from greenlet import getcurrent as get_ident
可以基於 greenlet -->> 粒度更細
比如 wsgi -- 有基於線程的,也有基於協程實現的
本地線程:
import threading
local_values = threading.local()
def func(num):
local_values.name = num
import time
time.sleep(1)
print(local_values.name, threading.current_thread().name)
for i in range(20):
th = threading.Thread(target=func, args=(i,), name='線程%s' % i)
th.start()
4 多app應用,以及web'訪問多app時的上下文
多app應用,通過前綴做分發
from werkzeug.wsgi import DispatcherMiddleware
from werkzeug.serving import run_simple
app1 = Flask('app1')
app2 = Flask('app2')
@app1.route('/index')
def index():
return 's'
@app2.route('/index')
def index():
return 's'
dm = DispatcherMiddleware(app1,{'/app2':app2})
if __name__ == '__main__':
run_simple('localhost',5000,dm)
同時並發的請求 app1 和 app2,請求上下文Local類中 {
'ID app1':{stack:[ReqeustContext,]},
'ID app2':{stack:[ReqeustContext,]},
}
5 補充 with .. 上下文管理
class SQLHelper(object):
def __enter__(self):
print('開始')
self.open()
return self
def open(self):
pass
def fetch(self):
pass
def close(self):
pass
def __exit__(self, exc_type, exc_val, exc_tb):
print('結束')
self.close()
with SQLHelper() as f:
pass
6 為什么 flask的 local 保存數據要使用 列表建成的棧
# 如果是 web 程序,棧中永遠是 一條數據 (可以不使用棧)
# 如果是 腳本測試 出現如下的上下文嵌套 ,會出現 多條數據
from flask import Flask,current_app,_app_ctx_stack
app1 = Flask(__name__)
app1.config['DEBUG'] = True
app2 = Flask(__name__)
app2.config['DEBUG'] = False
with app1.app_context():
print(_app_ctx_stack._local.__storage__)
print(current_app.config['DEBUG']) # current_app _app_ctx_stack.top [-1]
with app2.app_context():
print(_app_ctx_stack._local.__storage__)
print(current_app.config['DEBUG'])
# {5116: {'stack': [<flask.ctx.AppContext object at 0x00000000038C55C0>, <flask.ctx.AppContext object at 0x00000000038C5748>]}} False
