Flask 上下文管理-- (session,request,current_app的傳遞)--類似本地線程實現,以及多app應用


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM