一、前言
了解過flask的python開發者想必都知道flask中核心機制莫過于上下文管理,當然學習flask如果不了解其中的處理流程,可能在很多問題上不能得到解決,當然我在寫本篇文章之前也看到了很多博文有關于對flask上下文管理的剖析都非常到位,當然為了學習flask我也把對flask上下文理解寫下來供自己參考,也希望對其他人有所幫助。
二、知識儲備
threadlocal
在多線程中,線程間的數據是共享的, 但是每個線程想要有自己的數據該怎么實現? python中的threading.local對象已經實現,其原理是利用線程的唯一標識作為key,數據作為value來保存其自己的數據,以下是demo演示了多個線程同時修改同一變量的值的結果:
#!/usr/bin/env python3# -*- coding:utf-8 -*-# Author:wdimport threadingimport timevalues=threading.local()def run(arg): values.num=arg #修改threading.local對象的name數據 time.sleep(1) print(threading.current_thread().name,values.num) #打印values.numfor i in range(3): th = threading.Thread(target=run, args=(i,), name='run thread%s' % i) th.start()
結果:
run thread0 0
run thread1 1
run thread2 2
結果說明:
從結果中可以看到,values.num的值是不同的,按照普通線程理解因為有sleep存在,在每個線程最后打印values.num時候值應該都是2,但是正是因為threading.local對象內部會為每個線程開辟一個內存空間,從而使得每個線程都有自己的單獨數據,所以每個線程修改的是自己的數據(內部實現為字典),打印結果才不一樣。
有了以上的設計思想,我們可以自己定義類似于thread.local類,為了支持協程,將其唯一標識改為協程的唯一標識,其實這已經及其接近flask中的Local類了(后續在進行說明):
try: from greenlet import getcurrent as get_ident # 攜程唯一標識except ImportError: try: from thread import get_ident except ImportError: from _thread import get_ident # 線程唯一標識class Local(object): def __init__(self): object.__setattr__(self, 'storage', dict()) # 防止self.xxx 遞歸 object.__setattr__(self, '__get_ident__', get_ident) def __setattr__(self, key, value): ident = self.__get_ident__() # 獲取當前線程或協程的唯一標識 data = self.storage.get(ident) if not data: # 當前線程沒有數據 data = {key: value} # 創建數據 else: # 當前已經有數據 data[key] = value self.storage[ident] = data # 最后為當前線程設置其標識對應的數據 def __getattr__(self, name): try: return self.storage[self.__get_ident__()].get(name) # 返回name所對應的值 except KeyError: raise AttributeError(name)functools.partial
partial函數是工具包的一個不常用函數,其作用是給函數傳遞參數,同時返回的也是這個函數,但是這個函數的已經帶了參數了,示例:
新聞熱點
疑難解答