python语言线程标准库threading.local解读总结
本段源码可以学习的地方:
1.考虑到效率问题,可以通过上下文的机制,在属性被访问的时候临时构建;
2.可以重写一些魔术方法,比如__new__方法,在调用object.__new__(cls)前后进行属性的一些小设置;
3.在本库中使用的重写魔术方法,上下文这两种基础之上,我们可以想到函数装饰器,类装饰器,异常捕获,以及两种上下文的结构;
灵活运用这些手法,可以让我们在代码架构上更上一层,能够更加省时省力。
fromweakrefimportref#ref用在了构造大字典元素元组的第一个位置即(ref(Thread),线程字典)
fromcontextlibimportcontextmanager#上下文管理,用来确保__dict__属性的存在
fromthreadingimportcurrent_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自身的字典),...}
defget_dict(self):#从大字典中拿(ref(Thread),线程字典),然后取线程字典
thread=current_thread()
returnself.dicts[id(thread)][1]
defcreate_dict(self):#为当前线程创建一个线程字典,就是(ref(Thread),线程字典)[1],即元组的第二部分
localdict={}
key=self.key#key使用'_threading_local._localimpl.'+str(id(self)
thread=current_thread()#当前线程
idt=id(thread)#当前线程的id
deflocal_deleted(_,key=key):#这个函数不看pass
#Whenthelocalimplisdeleted,removethethreadattribute.
thread=wrthread()
ifthreadisnotNone:
delthread.__dict__[key]
defthread_deleted(_,idt=idt):#这个函数不看pass
#Whenthethreadisdeleted,removethelocaldict.
#Notethatthisissuboptimalifthethreadobjectgets
#caughtinareferenceloop.Wewouldliketobecalled
#assoonastheOS-levelthreadendsinstead.
local=wrlocal()
iflocalisnotNone:
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),小字典)
returnlocaldict
@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的
exceptKeyError:#如果拿不到报KeyError之后捕捉
dct=impl.create_dict()#然后再通过线程字典管理类临时创建一个
args,kw=impl.localargs#这个时候把拿到
self.__init__(*args,**kw)
withimpl.locallock:#通过上下文的方式上锁
object.__setattr__(self,'__dict__',dct)#给local()实例增加__dict__属性,这个属性指向大字典中value元组的第二个元素,即线程小字典
yield#到目前为止,local()类的两个属性都构造完成
classlocal:#local类
__slots__='_local__impl','__dict__'#local类有两个属性可以访问
def__new__(cls,*args,**kw):
if(argsorkw)and(cls.__init__isobject.__init__):#pass不看
raiseTypeError("Initializationargumentsarenotsupported")
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__implisipml即_localimp()
#__slots__规定了local()有两个属性,这里已经设置了一个_local__impl;
#第二个属性__dict__当我们以后在访问的时候使用上下文进行临时增加,比如第85行
impl.create_dict()#就是local._local__impl.create_dict()
returnself#返回这个配置好_local__impl属性的local()实例
def__getattribute__(self,name):#当我们取local()的属性时
with_patch(self):#会通过上下文先把数据准备好
returnobject.__getattribute__(self,name)#在准备好的数据中去拿要拿的属性name
def__setattr__(self,name,value):
ifname=='__dict__':#这个判断语句是控制local()实例的__dict__属性只能读不能被替换
raiseAttributeError(
"%robjectattribute'__dict__'isread-only"
%self.__class__.__name__)
with_patch(self):#同理,通过上下文先把__dict__构造好
returnobject.__setattr__(self,name,value)#然后调用基类的方法设置属性
def__delattr__(self,name):#删除属性,同理,和__setattr__手法相似
ifname=='__dict__':#这个判断语句是控制local()实例的__dict__属性只能读不能被替换
raiseAttributeError(
"%robjectattribute'__dict__'isread-only"
%self.__class__.__name__)
with_patch(self):#同理,通过上下文先把__dict__构造好
returnobject.__delattr__(self,name)
#整体架构图:
'''
/——key属性
/——dicts属性,格式{id(Thread):(ref(Thread),线程小字典)}
————:_local__impl属性----------是_local类的实例|
/——其他属性...|
//—————————————————————————————————————————————————————————————————————————————————/
创建一个local实例/
\/
\/
————:__dict__属性--------对应的是_local__impl属性的dicts中的线程小字典
'''
以上就是本次介绍的全部知识点内容,感谢大家的学习和对毛票票的支持。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。