您好,登錄后才能下訂單哦!
本篇內容介紹了“Flask的上下文管理詳解”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
Falsk完成線程安全的原理,是在啟動之后進程里維護request棧和app棧,棧是通過線程ID來保證每個請求的線程安全。
實現主要依賴三個類Local,LocalStack和LocalProxy,下面看一下具體的實現原理
三個類構建本地數據
1. Local
先看Local的源碼,實質并不是Flask中定義的,而是Flask依賴的werkzeug庫所定義。
可以看到其定義的兩個屬性__storage__, __ident_func__以及三個方法__getattr__,__setattr__,__release_local__。
1.屬性__storage__是多層級字典,第一層key是隱含的線程ID或者協程ID,第二層的key是實際使用的關鍵字
2.屬性__ident_func__可以看到是get_ident函數,get_ident函數要么是通過thread庫獲取當前執行單元的線程ID,要么是通過greenlet庫獲取當前執行協程的協程ID。
另外可以看到Local這個類的三個方法,實質是通過重寫Python內置函數__setattr__和__getattr__來實現線程或者協程間數據隔離
1.獲取local某屬性時如:local.age實質觸發的是__getattr__方法先獲取到當前線程ID——__ident_func__函數獲取,然后在__storage__字典中找到線程ident對應的結果集從獲取到的結果中再查找age屬性
2.設置local某屬性時如:local.age = 12 實際觸發的是__setattr__方法先獲取到當前線程ID——__ident_func__函數獲取,然后在__storage__字典設置相應的屬性字典集
另一個__release_local__方法就是將相應的線程數據刪除。
畫個簡圖比較起來更直觀一些。
主線程中生成一個對象local=Local(),三個線程中進行相同的操作local.no=每個線程對應的數。為每個線程都開辟一個存儲,所以誰來取或者存就找到自己對應中的位置,雖然取得key都一樣,但是每次存取都是只關于自己的值。
2. LocalStack
LocalStack也是定義在Flask所依賴的werkzeug庫,從字面意思來理解,它就是Local的堆棧操作,看一下源碼如何定義。
LocalStack實質就是圍繞著Local來進行操作,根據上面我們讀完Local的源碼可以看到,
LocalStack定義了一個Local對象
給這個對象設置了一個stack屬性,且這個屬性是一個列表
LocalStack中定義了對這個列表進行壓棧,出棧等方法
給類中的Local對象提供了自定義ident_func的方法
3. LocalProxy
LocalProxy字面意思就是做一個Local的代理,我們先從一個request的定義來看LocalProxy的用法,然后結合源碼來看LocalProxy到底是用來做什么?
類中稍微有些難理解的就是關于object.__setattr__(self, “_LocalProxy__local”, local)的作用,實際就是給self設置一個__local屬性。這是Python類中關于私有變量的定義。可以看Python的官方定義python私有變量。
可以看到這個類將所有Python類所內置的方法都進行重寫,重寫后所有的操作都是基于類中所定義的_get_current_object方法返回的對象進行操作。
而這個方法中返回值就是初始化時所給定的local對象執行返回的結果。如果創建時指定的不是Local對象,則直接執行此方法。如果給定的是Local對象,則根據類名查找對應的對象。
現在這個比較抽象,這個代理到底是做的什么? 我們結合Flask定義全局的request對象來看。假如我們想獲取請求的方法是什么,那我們使用的就是request.method。
下面是request定義的源碼
根據LocalProxy的源碼中重寫的__getattr__方法,先執行_get_current_object方法獲取到對象,然后再獲取返回對象method屬性。
創建LocalProxy時傳遞的函數是_lookup_req_object的偏函數,實際就是_lookup_req_object且name=request
再LocalProxy中__local就是一個函數,所以在執行_get_current_object就是執行_lookup_req_object且name=request返回的值,然后再取其method屬性
此時再執行_lookup_req_object函數,從_request_ctx_stack獲取top的request
使用Proxy可以簡單快捷的使用request.method獲取相應的值,其核心就是每次獲取時都會執行對應的函數,而函數中每次返回的值都是線程安全。保證數據正確且優雅。 否則我們每次都去執行一個函數來獲取其值,然后再取其屬性。
“Flask的上下文管理詳解”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。