侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

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

Python  /  管理员 发布于 7年前   187

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

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@contextmanagerdef _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 SQLAlchemy入门教程(基本用法)
    下一条:
    Python如何优雅获取本机IP方法
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 在python语言中Flask框架的学习及简单功能示例(0个评论)
    • 在Python语言中实现GUI全屏倒计时代码示例(0个评论)
    • Python + zipfile库实现zip文件解压自动化脚本示例(0个评论)
    • python爬虫BeautifulSoup快速抓取网站图片(1个评论)
    • vscode 配置 python3开发环境的方法(0个评论)
    • 近期文章
    • 智能合约Solidity学习CryptoZombie第三课:组建僵尸军队(高级Solidity理论)(0个评论)
    • 智能合约Solidity学习CryptoZombie第二课:让你的僵尸猎食(0个评论)
    • 智能合约Solidity学习CryptoZombie第一课:生成一只你的僵尸(0个评论)
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2018-04
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2022-01
    • 2023-07
    • 2023-10
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客