zoukankan      html  css  js  c++  java
  • python语言线程标准库threading.local源码解读

    本段源码可以学习的地方:

    1. 考虑到效率问题,可以通过上下文的机制,在属性被访问的时候临时构建;

    2. 可以重写一些魔术方法,比如 __new__ 方法,在调用 object.__new__(cls) 前后进行属性的一些小设置;

    3. 在本库中使用的重写魔术方法,上下文这两种基础之上,我们可以想到函数装饰器,类装饰器,异常捕获,以及两种上下文的结构;

    灵活运用这些手法,可以让我们在代码架构上更上一层,能够更加省时省力。

      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 '''
  • 相关阅读:
    80.常用的返回QuerySet对象的方法使用详解:order_by
    79.常用的返回QuerySet对象的方法使用详解: filter, exclude,annotate
    78.objects对象所属类原理分析
    69.ORM查询条件:isnull和regex的使用
    北邮 自考 互联网及其应用 考核指导
    北邮 自考 Java语言程序设计(一) 考核指导
    计算机网络自考群
    电气工程及自动化 (独立本科) 自考
    清华大学 研究生 培养方案
    windows10 M557 连接 匹配
  • 原文地址:https://www.cnblogs.com/duanming/p/11829354.html
Copyright © 2011-2022 走看看