python語言線程標準庫threading.local源碼解讀

本段源碼能夠學習的地方:架構

1. 考慮到效率問題,能夠經過上下文的機制,在屬性被訪問的時候臨時構建;函數

2. 能夠重寫一些魔術方法,好比 __new__ 方法,在調用 object.__new__(cls) 先後進行屬性的一些小設置;oop

3. 在本庫中使用的重寫魔術方法,上下文這兩種基礎之上,咱們能夠想到函數裝飾器,類裝飾器,異常捕獲,以及兩種上下文的結構;學習

靈活運用這些手法,可讓咱們在代碼架構上更上一層,可以更加省時省力。this

  1 from weakref import ref  # ref用在了構造大字典元素元組的第一個位置即 (ref(Thread), 線程字典)
  2 from contextlib import contextmanager  # 上下文管理,用來確保__dict__屬性的存在
  3 from threading import current_thread, RLock
  4 __all__ = ["local"]
  5 
  6 class _localimpl:  # local()._local__impl = _localimpl()  # local()實例的屬性_local__impl就是這個類的實例
  7     """一個管理線程字典的類"""
  8     __slots__ = 'key', 'dicts', 'localargs', 'locallock', '__weakref__'  # _local__impl有這麼多屬性
  9 
 10     def __init__(self):
 11         # 這個self.key是用在線程對象的字典中的key
 12         # self.key使用的一個字符串,這樣既能運行的快,
 13         # 可是經過'_threading_local._localimpl.' + str(id(self)也能保證不會衝突別的屬性
 14 
 15         self.key = '_threading_local._localimpl.' + str(id(self))
 16         #
 17         self.dicts = {}  # 大字典
 18         # 格式是: { id(線程1):(ref(Thread), 線程1自身的字典), id(線程2):(ref(Thread), 線程2自身的字典), ... }
 19 
 20     def get_dict(self):  # 從大字典中拿(ref(Thread), 線程字典), 而後取線程字典
 21         thread = current_thread()
 22         return self.dicts[id(thread)][1]
 23 
 24     def create_dict(self):  # 爲當前線程建立一個線程字典,就是(ref(Thread), 線程字典)[1],即元組的第二部分
 25         localdict = {}
 26         key = self.key  # key使用'_threading_local._localimpl.' + str(id(self)
 27         thread = current_thread()  # 當前線程
 28         idt = id(thread)  # 當前線程的id
 29         def local_deleted(_, key=key):  # 這個函數不看  pass
 30             # When the localimpl is deleted, remove the thread attribute.
 31             thread = wrthread()
 32             if thread is not None:
 33                 del thread.__dict__[key]
 34         def thread_deleted(_, idt=idt):  # 這個函數不看 pass
 35             # When the thread is deleted, remove the local dict.
 36             # Note that this is suboptimal if the thread object gets
 37             # caught in a reference loop. We would like to be called
 38             # as soon as the OS-level thread ends instead.
 39             local = wrlocal()
 40             if local is not None:
 41                 dct = local.dicts.pop(idt)
 42         wrlocal = ref(self, local_deleted)
 43         wrthread = ref(thread, thread_deleted)  # 大字典中每個線程對應的元素的第一個位置: (ref(Thread), 小字典)
 44         thread.__dict__[key] = wrlocal
 45         self.dicts[idt] = wrthread, localdict  # 在大字典中構造: id(thread) : (ref(Thread), 小字典)
 46         return localdict
 47 
 48 
 49 @contextmanager
 50 def _patch(self):
 51     impl = object.__getattribute__(self, '_local__impl')  # 此時的self是local(), 拿local()._local__impl
 52     try:
 53         dct = impl.get_dict()   # 而後從拿到的local()._local__impl調用線程字典管理類的local()._local__impl.get_dict()方法
 54                                 # 從20行到22這個get_dict()方法的定義能夠看出來,拿不到會報KeyError的
 55 
 56     except KeyError:  # 若是拿不到報 KeyError以後捕捉
 57         dct = impl.create_dict()  # 而後再經過線程字典管理類臨時建立一個
 58         args, kw = impl.localargs  # 這個時候把拿到
 59         self.__init__(*args, **kw)
 60     with impl.locallock:  # 經過上下文的方式上鎖
 61         object.__setattr__(self, '__dict__', dct)  # 給local() 實例增長__dict__屬性,這個屬性指向大字典中value元組的第二個元素,即線程小字典
 62         yield  # 到目前爲止,local()類的兩個屬性都構造完成
 63 
 64 
 65 class local:  # local類
 66     __slots__ = '_local__impl', '__dict__'  # local類有兩個屬性能夠訪問
 67 
 68     def __new__(cls, *args, **kw):
 69         if (args or kw) and (cls.__init__ is object.__init__):  # pass不看
 70             raise TypeError("Initialization arguments are not supported")
 71         self = object.__new__(cls)  # pass不看
 72         impl = _localimpl()  # _local_impl屬性對應的是_localimpl類的實例
 73         impl.localargs = (args, kw)  # _local_impl屬性即_localimpl類的實例 的 localargs屬性是一個元組
 74         impl.locallock = RLock()  # pass 不看
 75         object.__setattr__(self, '_local__impl', impl)
 76         # 把_local__impl 增長給local(), 因此:local()._local__impl is ipml 即 _localimp()
 77 
 78         # __slots__規定了local()有兩個屬性,這裏已經設置了一個_local__impl;
 79         # 第二個屬性__dict__當咱們之後在訪問的時候使用上下文進行臨時增長,好比第85行
 80 
 81         impl.create_dict()  # 就是local._local__impl.create_dict()
 82         return self  # 返回這個配置好_local__impl屬性的local()實例
 83 
 84     def __getattribute__(self, name):  # 當咱們取local()的屬性時
 85         with _patch(self):  # 會經過上下文先把數據準備好
 86             return object.__getattribute__(self, name)  # 在準備好的數據中去拿要拿的屬性name
 87 
 88     def __setattr__(self, name, value):
 89         if name == '__dict__':  # 這個判斷語句是控制local()實例的__dict__屬性只能讀不能被替換
 90             raise AttributeError(
 91                 "%r object attribute '__dict__' is read-only"
 92                 % self.__class__.__name__)
 93         with _patch(self):  # 同理, 經過上下文先把__dict__構造好
 94             return object.__setattr__(self, name, value)  # 而後調用基類的方法設置屬性
 95 
 96     def __delattr__(self, name):  # 刪除屬性,同理,和__setattr__手法類似
 97         if name == '__dict__':   # 這個判斷語句是控制local()實例的__dict__屬性只能讀不能被替換
 98             raise AttributeError(
 99                 "%r object attribute '__dict__' is read-only"
100                 % self.__class__.__name__)
101         with _patch(self):  # 同理, 經過上下文先把__dict__構造好
102             return object.__delattr__(self, name)
103 
104 # 總體架構圖:
105 '''
106 
107                                                                                / ——  key 屬性
108                                                                               /  ——  dicts 屬性, 格式{id(Thread):(ref(Thread), 線程小字典)}
109                         ———— : _local__impl屬性   ----------  是_local類的實例                                                     |
110                       /                                                          —— 其餘屬性...                                    |
111                      /                          /—————————————————————————————————————————————————————————————————————————————————/
112     建立一個local實例                           /
113                      \                        /
114                       \                     /
115                         ———— : __dict__屬性  --------  對應的是_local__impl屬性的dicts 中的線程小字典
116 
117 
118 
119 '''
相關文章
相關標籤/搜索