python thread local,threading.thread python
在同一个进程下,多个线程共享进程的数据。为了保证数据的安全性,多线程写会被锁死,也就是说多线程模式下效率会降低。
Threading.local()可以为每个线程创建一个本地名称空间。threading.local()是全局的,所有线程都可以访问,但是放入threading.local()对象的属性数据不会受到其他线程的干扰。
threading.local实现线程数据隔离的主要原理是通过一个大字典,大字典的键值存储线程的id,值是一个小字典存储线程的局部变量组成的字典。
知识储备:
1.插槽__变量:
实例化时__dict__属性受到限制,每次实例化都需要分配一个新的dict,所以大量实例化这个类存在空间浪费;如果一个类的属性被确定,它可以被__slots__变量限制。__slots__配置后,只能动态添加和修改__slots__中的属性,不能添加其他属性,所以没有__dict。
https://blog.csdn.net/sxingming/article/details/52892640
2.contextmanager上下文管理器
从上下文库导入上下文管理器
作为一个contextmanager,上下文管理器主要用来准备一些逻辑的执行,以及处理一些逻辑的善后工作。
contextmanager主要实现了两个方法__enter__(在托管逻辑执行之前执行)和__exit__(在托管逻辑执行之后执行)。您可以直接定制这两个函数来实现定制的上下文管理器。
使用contextmanager注释函数后,可以用。yeild之前的内容相当于__enter__,yelid之后的内容相当于_ _ exit _ _当函数遇到yield时,它在yield处停止,并返回yield后的值。执行完所有带的语句后,在yield之后执行语句。
资源链接
3、python弱引用weakref
Python的垃圾收集主要使用引用计数、标记清除和世代回收机制;Python为每个对象维护一个引用计数器。当引用被创建或复制时,引用计数器为1,当对象被销毁时,引用计数器为-1。值为0意味着没有引用,这将释放内存。
明确:解决循环引用问题。
世代循环:以空间换时间,提高垃圾收集效率;生存时间越长,扫描间隔越长,减少频繁扫描造成的资源消耗。
但是,通过调用weakref模块的ref来创建对象的弱引用不会生成引用计数,但是可以操作所指向的对象。
https://www.cnblogs.com/goldsunshine/p/16307598.html
threading.local()的源代码分析:
Threading.local类使用一个_localimpl类作为每个线程的局部变量的管理类,用来以大字典的形式存储每个线程的局部变量;_localimpl的操作实际上是一个局部变量大字典的操作。
_localiml线程管理类的主要功能是创建或获取线程局部变量的字典。
# { id(Thread) - (ref(Thread),线程本地字典)}
# id (thread 1):(ref(Thread),thread 1局部变量字典),
class _localimpl:
管理线程字典的类。
# local()。_local__impl=_localimpl()
# local()实例的attribute _local__impl是该类的一个实例。
_local_impl只有这么多属性
__slots__=key , dicts , localargs , locallock , __weakref__
def __init__(self):
# self.key线程对象中使用的键
self.key=_threading_local。_localimpl。str(id(self))
#大字典,格式{}
# { id(Thread) - (ref(Thread),线程本地字典)}
# id (thread 1):(ref(Thread),thread 1局部变量字典),
self.dicts={}
def get_dict(self):
#从大字典self.dicts中获取线程局部变量字典
thread=当前线程()
返回self.dicts[id(thread)][1]
def create_dict(self):
#为当前线程创建一个线程局部变量字典
localdict={}
key=自我. key
Thread=current_thread() #当前线程
Idt=id(thread) #当前线程id
def local_deleted(_,key=key):
#定义一个弱引用的回调函数,在线程局部变量的管理类localimpl被删除时,从线程中删除相应的变量。
thread=wrthread()
如果线程不是无:
德尔螺纹__dict__[key]
def thread_deleted(_,idt=idt):
# 定义一个弱引用的回调函数,当线程被删除时,在管理类localimpl对象的字典中删除该线程的字典项
local=wrlocal()
如果本地不为无:
dct=local.dicts.pop(idt)
# 定义两个弱引用
wrlocal=ref(self,local_deleted)
wrthread=ref(thread,thread_deleted)
# 线程和局部变量管理类相互关联
线程__dict__[key]=wrlocal
#在字典中以线程编号为钥匙,保存了弱引用和线程局部变量的字典
self.dicts[idt]=wrthread,localdict
# { id(线程)- (ref(线程)),线程本地字典)}
# id(线程1):(参考(螺纹),线程一局部变量字典),
返回本地字典
当地的类中通过__插槽_ _变量定义了两个变量本地__impl和_ _字典_,_本地_ _实现用来保存上述局部变量管理类_localimpl,dict__则保存当地的类自己的成员函数或变量,可以通过self.xxx来引用到当地。类中重载了__getattribute,setattr,_ _ delattr _ _等函数,通过重载这些函数,将当地的类中的__词典_ _对象指向了_本地_ _实现中保存的该线程的局部变量字典,对当地的类进行赋值和获取操作时,实际上是对_本地_ _实现中保存的该线程的局部变量字典进行操作。
@上下文管理器
def _patch(self): # self是本地()
# 拿到本地()的属性_local__impl,_local__impl即是_localimpl()实例化的对象
impl=对象. getattribute__(self, _local__impl )
尝试:
dct=impl.get_dict() #获取线程字典局部变量字典
除了关键错误:
dct=impl.create_dict() #抛出键错误,则创建线程局部变量字典
args,kw=impl.localargs
自我. init _ _(*参数,* *千瓦)
with impl.locallock: #通过上下文方式加锁impl.locallock - Rlock()
对象. self _ _ setattr _ _(self, __dict__ ,dct) #给本地()增加__词典_ _属性,指向线程小字典,即线程局部变量字典(指向字典,并非设置字典中的局部属性)
产量
本地类别:
#本地()只有两个属性
__slots__=_local__impl , __dict__
def __new__(cls,/,*args,**kw):
if(参数或千瓦)和(cls .__init__是对象. init__):
引发TypeError(“不支持初始化参数")
自我=对象. new__(cls) #父类目标创建类对象
impl=_localimpl() # _localimpl实例化
impl.localargs=(args,kw)
impl.locallock=RLock()
# 设置本地()属性_local__impl,赋值为_localimpl的实例化对象
对象__setattr__(self, _local__impl ,impl)
# 调用_localimpl的create_dict()函数创建小字典(线程局部变量字典)
impl.create_dict()
回归自我#返回配置好_本地_ _实现属性的本地()实例
# 重载getattribute、setattr、delattr
# getattribute、setattr、delattr操作loacl()实例,实际是操作
# _localimpl,来对线程局部变量字典的操作
def __getattribute__(self,name):
带补丁(自身):#通过上下文管理准备数据
返回对象. getattribute__(self,name) #通过上下文配置好本地()的__词典_ _中的数据后,直接到本地()的__词典_ _中拿
def __setattr__(self,name,value):
if name==__dict__: # local()的__词典_ _只读,不能设置和倒三角形
引发属性错误(
%r对象属性" __词典_ _ "是只读的
%自我__类_ _ .__name__)
带补丁(自身):
返回对象__setattr__(自己,姓名,值)
def __delattr__(self,name):
if name==__dict__ :
引发属性错误(
%r对象属性" __词典_ _ "是只读的
%自我__类_ _ .__name__)
带补丁(自身):
返回对象. delattr__(自己,名字)
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。