温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

python语言线程标准库threading.local有什么用

发布时间:2021-08-25 11:16:39 来源:亿速云 阅读:190 作者:小新 栏目:开发技术

小编给大家分享一下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语言线程标准库threading.local有什么用”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI