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(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。