python语言线程标准库threading.local解读总结

 更新时间:2019年11月10日 14:24:13   作者:段明  
在本篇文章里我们给各位整理了一篇关于python threading.local源码解读的相关文章知识点,有需要的朋友们可以学习下。

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

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

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

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

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

from weakref import ref # ref用在了构造大字典元素元组的第一个位置即 (ref(Thread), 线程字典)
from contextlib import contextmanager # 上下文管理,用来确保__dict__属性的存在
from threading import current_thread, RLock
__all__ = ["local"]

class _localimpl: # local()._local__impl = _localimpl() # local()实例的属性_local__impl就是这个类的实例
  """一个管理线程字典的类"""
  __slots__ = 'key', 'dicts', 'localargs', 'locallock', '__weakref__' # _local__impl有这么多属性

  def __init__(self):
    # 这个self.key是用在线程对象的字典中的key
    # self.key使用的一个字符串,这样既能运行的快,
    # 但是通过'_threading_local._localimpl.' + str(id(self)也能保证不会冲突别的属性

    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): # 为当前线程创建一个线程字典,就是(ref(Thread), 线程字典)[1],即元组的第二部分
    localdict = {}
    key = self.key # key使用'_threading_local._localimpl.' + str(id(self)
    thread = current_thread() # 当前线程
    idt = id(thread) # 当前线程的id
    def local_deleted(_, key=key): # 这个函数不看 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): # 这个函数不看 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) # 大字典中每一个线程对应的元素的第一个位置: (ref(Thread), 小字典)
    thread.__dict__[key] = wrlocal
    self.dicts[idt] = wrthread, localdict # 在大字典中构造: id(thread) : (ref(Thread), 小字典)
    return localdict


@contextmanager
def _patch(self):
  impl = object.__getattribute__(self, '_local__impl') # 此时的self是local(), 拿local()._local__impl
  try:
    dct = impl.get_dict()  # 然后从拿到的local()._local__impl调用线程字典管理类的local()._local__impl.get_dict()方法
                # 从20行到22这个get_dict()方法的定义可以看出来,拿不到会报KeyError的

  except KeyError: # 如果拿不到报 KeyError之后捕捉
    dct = impl.create_dict() # 然后再通过线程字典管理类临时创建一个
    args, kw = impl.localargs # 这个时候把拿到
    self.__init__(*args, **kw)
  with impl.locallock: # 通过上下文的方式上锁
    object.__setattr__(self, '__dict__', dct) # 给local() 实例增加__dict__属性,这个属性指向大字典中value元组的第二个元素,即线程小字典
    yield # 到目前为止,local()类的两个属性都构造完成


class local: # local类
  __slots__ = '_local__impl', '__dict__' # local类有两个属性可以访问

  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属性对应的是_localimpl类的实例
    impl.localargs = (args, kw) # _local_impl属性即_localimpl类的实例 的 localargs属性是一个元组
    impl.locallock = RLock() # pass 不看
    object.__setattr__(self, '_local__impl', impl)
    # 把_local__impl 增加给local(), 所以:local()._local__impl is ipml 即 _localimp()

    # __slots__规定了local()有两个属性,这里已经设置了一个_local__impl;
    # 第二个属性__dict__当我们以后在访问的时候使用上下文进行临时增加,比如第85行

    impl.create_dict() # 就是local._local__impl.create_dict()
    return self # 返回这个配置好_local__impl属性的local()实例

  def __getattribute__(self, name): # 当我们取local()的属性时
    with _patch(self): # 会通过上下文先把数据准备好
      return object.__getattribute__(self, name) # 在准备好的数据中去拿要拿的属性name

  def __setattr__(self, name, value):
    if name == '__dict__': # 这个判断语句是控制local()实例的__dict__属性只能读不能被替换
      raise AttributeError(
        "%r object attribute '__dict__' is read-only"
        % self.__class__.__name__)
    with _patch(self): # 同理, 通过上下文先把__dict__构造好
      return object.__setattr__(self, name, value) # 然后调用基类的方法设置属性

  def __delattr__(self, name): # 删除属性,同理,和__setattr__手法相似
    if name == '__dict__':  # 这个判断语句是控制local()实例的__dict__属性只能读不能被替换
      raise AttributeError(
        "%r object attribute '__dict__' is read-only"
        % self.__class__.__name__)
    with _patch(self): # 同理, 通过上下文先把__dict__构造好
      return object.__delattr__(self, name)

# 整体架构图:
'''

                                        / —— key 属性
                                       / —— dicts 属性, 格式{id(Thread):(ref(Thread), 线程小字典)}
            ———— : _local__impl属性  ---------- 是_local类的实例                           |
           /                             —— 其他属性...                  |
           /             /—————————————————————————————————————————————————————————————————————————————————/
  创建一个local实例              /
           \            /
           \           /
            ———— : __dict__属性 -------- 对应的是_local__impl属性的dicts 中的线程小字典



'''

以上就是本次介绍的全部知识点内容,感谢大家的学习和对脚本之家的支持。

相关文章

  • Python计算图片数据集的均值方差示例详解

    Python计算图片数据集的均值方差示例详解

    这篇文章主要为大家介绍了Python计算图片数据集的均值方差,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05
  • Django websocket原理及功能实现代码

    Django websocket原理及功能实现代码

    这篇文章主要介绍了Django websocket原理及功能实现代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-11-11
  • 如何在conda虚拟环境中配置cuda+cudnn+pytorch深度学习环境

    如何在conda虚拟环境中配置cuda+cudnn+pytorch深度学习环境

    这篇文章主要介绍了如何在conda虚拟环境中配置cuda+cudnn+pytorch深度学习环境,想在服务器上配置深度学习的环境,看了很多资料后总结出来了对于新手比较友好的配置流程,需要的朋友可以参考下
    2023-03-03
  • python Django框架快速入门教程(后台管理)

    python Django框架快速入门教程(后台管理)

    Django 是一个开放源代码的 Web 应用框架,由 Python 写成,今天通过本文给大家介绍python Django框架快速入门教程,适用后台管理,感兴趣的朋友跟随小编一起看看吧
    2021-07-07
  • tensorflow 只恢复部分模型参数的实例

    tensorflow 只恢复部分模型参数的实例

    今天小编就为大家分享一篇tensorflow 只恢复部分模型参数的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-01-01
  • Python生成扫雷地图的方法

    Python生成扫雷地图的方法

    这篇文章主要为大家详细介绍了Python生成扫雷地图的方法,并非游戏实现,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09
  • python爬虫爬取图片的简单代码

    python爬虫爬取图片的简单代码

    在本篇文章里小编给大家整理的是一篇关于python爬虫爬取图片的简单代码内容,有兴趣的朋友们可以测试下。
    2021-01-01
  • Python的SQLAlchemy框架使用入门

    Python的SQLAlchemy框架使用入门

    这篇文章主要介绍了Python的SQLAlchemy框架使用入门,SQLAlchemy框架是Python中用来操作数据库的ORM框架之一,需要的朋友可以参考下
    2015-04-04
  • Python详解如何动态给对象增加属性和方法

    Python详解如何动态给对象增加属性和方法

    python是动态语⾔,动态编程语⾔是⾼级程序设计语⾔的⼀个类别,在计算机科学领域已被⼴泛应⽤。它是⼀类在 运⾏时可以改变其结构 的语⾔ :例如新的函数、对象、甚⾄代码可以被引进,已有的函数可以被删除或是其他结构上的变化
    2022-07-07
  • python实现word 2007文档转换为pdf文件

    python实现word 2007文档转换为pdf文件

    这篇文章主要为大家详细介绍了python实现word 2007文档转换为pdf文件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-03-03

最新评论