python語言線程標(biāo)準(zhǔn)庫threading.local解讀總結(jié)
本段源碼可以學(xué)習(xí)的地方:
1. 考慮到效率問題,可以通過上下文的機(jī)制,在屬性被訪問的時(shí)候臨時(shí)構(gòu)建;
2. 可以重寫一些魔術(shù)方法,比如 __new__ 方法,在調(diào)用 object.__new__(cls) 前后進(jìn)行屬性的一些小設(shè)置;
3. 在本庫中使用的重寫魔術(shù)方法,上下文這兩種基礎(chǔ)之上,我們可以想到函數(shù)裝飾器,類裝飾器,異常捕獲,以及兩種上下文的結(jié)構(gòu);
靈活運(yùn)用這些手法,可以讓我們?cè)诖a架構(gòu)上更上一層,能夠更加省時(shí)省力。
from weakref import ref # ref用在了構(gòu)造大字典元素元組的第一個(gè)位置即 (ref(Thread), 線程字典) from contextlib import contextmanager # 上下文管理,用來確保__dict__屬性的存在 from threading import current_thread, RLock __all__ = ["local"] class _localimpl: # local()._local__impl = _localimpl() # local()實(shí)例的屬性_local__impl就是這個(gè)類的實(shí)例 """一個(gè)管理線程字典的類""" __slots__ = 'key', 'dicts', 'localargs', 'locallock', '__weakref__' # _local__impl有這么多屬性 def __init__(self): # 這個(gè)self.key是用在線程對(duì)象的字典中的key # self.key使用的一個(gè)字符串,這樣既能運(yùn)行的快, # 但是通過'_threading_local._localimpl.' + str(id(self)也能保證不會(huì)沖突別的屬性 self.key = '_threading_local._localimpl.' + str(id(self)) # self.dicts = {} # 大字典 # 格式是: { id(線程1):(ref(Thread), 線程1自身的字典), id(線程2):(ref(Thread), 線程2自身的字典), ... } def get_dict(self): # 從大字典中拿(ref(Thread), 線程字典), 然后取線程字典 thread = current_thread() return self.dicts[id(thread)][1] def create_dict(self): # 為當(dāng)前線程創(chuàng)建一個(gè)線程字典,就是(ref(Thread), 線程字典)[1],即元組的第二部分 localdict = {} key = self.key # key使用'_threading_local._localimpl.' + str(id(self) thread = current_thread() # 當(dāng)前線程 idt = id(thread) # 當(dāng)前線程的id def local_deleted(_, key=key): # 這個(gè)函數(shù)不看 pass # When the localimpl is deleted, remove the thread attribute. thread = wrthread() if thread is not None: del thread.__dict__[key] def thread_deleted(_, idt=idt): # 這個(gè)函數(shù)不看 pass # When the thread is deleted, remove the local dict. # Note that this is suboptimal if the thread object gets # caught in a reference loop. We would like to be called # as soon as the OS-level thread ends instead. local = wrlocal() if local is not None: dct = local.dicts.pop(idt) wrlocal = ref(self, local_deleted) wrthread = ref(thread, thread_deleted) # 大字典中每一個(gè)線程對(duì)應(yīng)的元素的第一個(gè)位置: (ref(Thread), 小字典) thread.__dict__[key] = wrlocal self.dicts[idt] = wrthread, localdict # 在大字典中構(gòu)造: id(thread) : (ref(Thread), 小字典) return localdict @contextmanager def _patch(self): impl = object.__getattribute__(self, '_local__impl') # 此時(shí)的self是local(), 拿local()._local__impl try: dct = impl.get_dict() # 然后從拿到的local()._local__impl調(diào)用線程字典管理類的local()._local__impl.get_dict()方法 # 從20行到22這個(gè)get_dict()方法的定義可以看出來,拿不到會(huì)報(bào)KeyError的 except KeyError: # 如果拿不到報(bào) KeyError之后捕捉 dct = impl.create_dict() # 然后再通過線程字典管理類臨時(shí)創(chuàng)建一個(gè) args, kw = impl.localargs # 這個(gè)時(shí)候把拿到 self.__init__(*args, **kw) with impl.locallock: # 通過上下文的方式上鎖 object.__setattr__(self, '__dict__', dct) # 給local() 實(shí)例增加__dict__屬性,這個(gè)屬性指向大字典中value元組的第二個(gè)元素,即線程小字典 yield # 到目前為止,local()類的兩個(gè)屬性都構(gòu)造完成 class local: # local類 __slots__ = '_local__impl', '__dict__' # local類有兩個(gè)屬性可以訪問 def __new__(cls, *args, **kw): if (args or kw) and (cls.__init__ is object.__init__): # pass不看 raise TypeError("Initialization arguments are not supported") self = object.__new__(cls) # pass不看 impl = _localimpl() # _local_impl屬性對(duì)應(yīng)的是_localimpl類的實(shí)例 impl.localargs = (args, kw) # _local_impl屬性即_localimpl類的實(shí)例 的 localargs屬性是一個(gè)元組 impl.locallock = RLock() # pass 不看 object.__setattr__(self, '_local__impl', impl) # 把_local__impl 增加給local(), 所以:local()._local__impl is ipml 即 _localimp() # __slots__規(guī)定了local()有兩個(gè)屬性,這里已經(jīng)設(shè)置了一個(gè)_local__impl; # 第二個(gè)屬性__dict__當(dāng)我們以后在訪問的時(shí)候使用上下文進(jìn)行臨時(shí)增加,比如第85行 impl.create_dict() # 就是local._local__impl.create_dict() return self # 返回這個(gè)配置好_local__impl屬性的local()實(shí)例 def __getattribute__(self, name): # 當(dāng)我們?nèi)ocal()的屬性時(shí) with _patch(self): # 會(huì)通過上下文先把數(shù)據(jù)準(zhǔn)備好 return object.__getattribute__(self, name) # 在準(zhǔn)備好的數(shù)據(jù)中去拿要拿的屬性name def __setattr__(self, name, value): if name == '__dict__': # 這個(gè)判斷語句是控制local()實(shí)例的__dict__屬性只能讀不能被替換 raise AttributeError( "%r object attribute '__dict__' is read-only" % self.__class__.__name__) with _patch(self): # 同理, 通過上下文先把__dict__構(gòu)造好 return object.__setattr__(self, name, value) # 然后調(diào)用基類的方法設(shè)置屬性 def __delattr__(self, name): # 刪除屬性,同理,和__setattr__手法相似 if name == '__dict__': # 這個(gè)判斷語句是控制local()實(shí)例的__dict__屬性只能讀不能被替換 raise AttributeError( "%r object attribute '__dict__' is read-only" % self.__class__.__name__) with _patch(self): # 同理, 通過上下文先把__dict__構(gòu)造好 return object.__delattr__(self, name) # 整體架構(gòu)圖: ''' / —— key 屬性 / —— dicts 屬性, 格式{id(Thread):(ref(Thread), 線程小字典)} ———— : _local__impl屬性 ---------- 是_local類的實(shí)例 | / —— 其他屬性... | / /—————————————————————————————————————————————————————————————————————————————————/ 創(chuàng)建一個(gè)local實(shí)例 / \ / \ / ———— : __dict__屬性 -------- 對(duì)應(yīng)的是_local__impl屬性的dicts 中的線程小字典 '''
以上就是本次介紹的全部知識(shí)點(diǎn)內(nèi)容,感謝大家的學(xué)習(xí)和對(duì)腳本之家的支持。
相關(guān)文章
Python cookbook(數(shù)據(jù)結(jié)構(gòu)與算法)從任意長(zhǎng)度的可迭代對(duì)象中分解元素操作示例
這篇文章主要介紹了Python 數(shù)據(jù)結(jié)構(gòu)與算法 從任意長(zhǎng)度的可迭代象中分解元素操作,結(jié)合實(shí)例形式分析了Python使用*表達(dá)式針對(duì)可迭代對(duì)象的分解操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2018-02-02PyQt5 QLineEdit輸入的子網(wǎng)字符串校驗(yàn)QRegExp實(shí)現(xiàn)
這篇文章主要介紹了PyQt5 QLineEdit輸入的子網(wǎng)字符串校驗(yàn)QRegExp實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04Python輸入正負(fù)10進(jìn)制,轉(zhuǎn)4位16進(jìn)制問題
這篇文章主要介紹了Python輸入正負(fù)10進(jìn)制,轉(zhuǎn)4位16進(jìn)制問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06利用Python編寫一個(gè)注冊(cè)機(jī)用于生成卡密
這篇文章主要為大家詳細(xì)介紹了如何利用Python編寫一個(gè)注冊(cè)機(jī)用于生成卡密(兌換碼),并使用這些卡密登錄應(yīng)用程序,感興趣的小伙伴可以了解下2023-11-11Python實(shí)現(xiàn)檢測(cè)服務(wù)器是否可以ping通的2種方法
這篇文章主要介紹了Python實(shí)現(xiàn)檢測(cè)服務(wù)器是否可以ping通的2種方法,本文分別講解了使用ping和fping命令檢測(cè)服務(wù)器是否可以ping通,需要的朋友可以參考下2015-01-01Python中嘗試多線程編程的一個(gè)簡(jiǎn)明例子
這篇文章主要介紹了Python中嘗試多線程編程的一個(gè)簡(jiǎn)明例子,由于GIL的存在,Python中的多線程編程一個(gè)是熱點(diǎn)和難點(diǎn)問題,需要的朋友可以參考下2015-04-04用Python每天自動(dòng)給女友免費(fèi)發(fā)短信
大家好,本篇文章主要講的是用Python每天自動(dòng)給女友免費(fèi)發(fā)短信,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽2021-12-12