1.1.local線程隔離對象
不用local對象的情況
from threading import Thread request = '123' class MyThread(Thread): def run(self): global request request = 'abc' print('子線程',request) #子線程 abc mythread = MyThread() mythread.start() mythread.join() print('主線程',request) #主線程 abc
如果用local對象,在每個線程中都是隔離的
from threading import Thread from werkzeug.local import Local locals = Local() locals.request = '123' class MyThread(Thread): def run(self): locals.request = 'abc' print('子線程',locals.request) #子線程 abc mythread = MyThread() mythread.start() mythread.join() print('主線程',locals.request) #主線程 123
1.2.app上下文和request上下文
應用上下文和請求上下文都是存放在一個‘LocalStack’的棧中,和應用app相關的操作就必須要用到應用上下文,比如通過current_app獲取當前的這個app的名字。和請求相關的操作就必須用到請求上下文,比如使用url_for反轉視圖函數。
- 在視圖函數中,不用擔心上下文的問題,因為視圖函數要執行,name肯定是通過訪問url的方式執行的,name這種情況下,Flask底層就已經自動的幫我們把請求上年文和應用上下文都推入到了相應的棧中。
- 如果想要在視圖函數外面執行相關的操作,name就必須要手動推入相關的上下文
- 手動推入請求上下文:推入請求上下文到棧中,會首先判斷有沒有應用上下文,如果沒有那么就會先推入應用上下文到棧中,然后再推入請求上下文到棧中。
app上下文
from flask import Flask,current_app app = Flask(__name__) #如果在視圖函數外部訪問,則必須手動推入一個app上下文到app上下文棧中 #第一種方法 # app_context = app.app_context() # app_context.push() # print(current_app.name) #第二種方法 with app.app_context(): print(current_app.name) #context_demo @app.route('/') def index(): # 在視圖函數內部可以直接訪問current_app.name print(current_app.name) #context_demo return 'Hello World!' if __name__ == '__main__': app.run(debug=True)
請求上下文
from flask import Flask,current_app,url_for app = Flask(__name__) #應用上下文 #如果在視圖函數外部訪問,則必須手動推入一個app上下文到app上下文棧中 with app.app_context(): print(current_app.name) #context_demo @app.route('/') def index(): # 在視圖函數內部可以直接訪問current_app.name print(current_app.name) #context_demo return 'Hello World!' @app.route('/list/') def my_list(): return 'my_list' # 請求上下文 with app.test_request_context(): # 手動推入一個請求上下文到請求上下文棧中 # 如果當前應用上下文棧中沒有應用上下文 # 那么會首先推入一個應用上下文到棧中 print(url_for('my_list')) if __name__ == '__main__': app.run(debug=True)
為什么上下文需要放在棧中?
1.應用上下文:
Flask底層是基於werkzeug,werkzeug是可以包含多個app的,所以這時候用一個棧來保存,如果你在使用app1,那么app1應該是要在棧的頂部,如果用完了app1那么app應該從棧中刪除,方便其他代碼使用下面的app。
2.請求上下文:
如果在寫測試代碼,或者離線腳本的時候,我們有時候可能需要創建多個請求上下文,這時候就需要存放到一個棧中了。使用哪個請求上下文的時候,就把對應的請求上下文放到棧的頂部,用完了就要把這個請求上下文從棧中移除掉。
1.3.線程隔離的g對象
g對象是在整個Flask應用運行期間都是可以使用的,並且它也是跟request一樣是線程隔離的。這個對象是專門用來存儲開發者自定義的一些數據,方便在整個Flask程序中都可以使用。一般使用就是,將一些經常會用到的數據綁定到上面,以后就直接從g上面取就可以了,而不是通過傳參的形式,這樣更加方便。