threadiing.local和高级用法
1.threading.local介绍
threading.local()方法:给每一个线程开辟自己的空间,来存储自己的数据。在里面封装这一些对应此线程
注意:
虽然flask没有threading.local(),但是flask内部实现了一个和threading.local()类似的功能~
代码实现
from threading import local import threading import time class Foo(object): def __init__(self): self.num = 0 # 当每个线程在执行 val1.xx=1 ,在内部会为此线程开辟一个空间,来存储 xx=1 # val1.xx,找到此线程自己的内存地址去取自己存储 xx,根据线程的id来进行区分线程。 val1 = local() val = Foo() def func(item): val1 = item val.num = val1 time.sleep(3) # print(val.num) print(val1) if __name__ == '__main__': for item in range(5): t = threading.Thread(target=func,args=(item,)) t.start()
2.为什么要写threading.local的用法,和flask有什么关系嘛
这是因为在flask中有个local类,他和threading.local的功能一样,为每个线程开辟空间进行存取数据,他们两个的内部实现机制一样,内部维护一个字典,以线程(协程)ID为key,进行数据隔离。(个人觉得加锁可以,但是效率就会降低)
3.通过代码来实现一个threading.local的功能
在了解flask里面的local类功能之前,可以通过栈,面相对象,和线程的知识爱实现一个自己写的threading.loca()的功能
知识点一:栈
栈:栈是具有后进先出的特性,列子是弹夹,可以使用列表的append和pop方法将列表维护成一个栈
应用场景:
drf源码中的节流组件
知识点二:面向对象相关
class Foo(object): def __setattr__(self, key, value): print(key,value) def __getattr__(self, item): item =456 return item # obj = Foo() # 实例化执行的是__init__方法 # obj.x =123 # 在obj.x 后面加=是代表赋值,会自动的执行__setattr__方法。其中key=x,value=123 # print(obj.x) # 在obj.x 后面不加=的时候,是获取值,执行__getattr__方法,其中x=456,是__getattr__的返回值 # 应用: # 在drf的request里面,新的request.data和request.quert_parmas是新封装的request对象 # 但是新的request依然可以使用request.POST,是因为在新的erequest里面有一个__getattr__ # 方法,一旦自己的类里面没有该方法,就会执行老的request里面的POST方法
__attr__的应用(小列子)
# 看如下代码:会返回什么?
class Local(object): def __init__(self): self.storage = {} def __setattr__(self, key, value): self.storage[key] = value def __getattr__(self, item): return self.storage.get(item) local = Local() # local = Local(),执行了__init__方法里面的self.storage = {} # 其中self.storage = {}相当于是赋值操作,所以会调用自己的__setattr__方法 # 但是其中的self.strorage(后面的不是)是来获取值了(整句的意思是将vale赋值给storage,但是这里面没有,必须的先获取在赋值),就会去执行__getattr__方法 # 但是__getattr__连的self.storage又去获取值去了,又去执行__getattr__方法,造成递归,所以程序报错 # 所以我们可以换一中写法,在__init__继承父类的__setattr__方法 class Local(object): def __init__(self): object.__setattr__(self,"storage",{}) # 这种赋值是在给父类的__setattr__对象里面创建了一个 storage = {} 的字典 # 实力化对象在执行__init__的时候会在storage = { 'key':{1:"123"}}字典里面赋值 # 也可以防止上面的递归发生 def __setattr__(self, key, value): self.storage[key] = value def __getattr__(self, item): return self.storage.get(item) local = Local() local.key = {1:"123"} # 可以设置值了 print(local.x) # 可以获取值了,但是为空,因为没设置 print(local.storage) # 也可以获取storage字典 print(local.key) # 也可以获取key字典 print(local.__dict__) # # __dict__是将对象里面的字典类型转成字典
知识点三:线程唯一id
import threading from threading import get_ident # 通过模块获取线程的唯一标识,可以理解为线程的id def task(): ident = get_ident() print(ident) for i in range(4): t = threading.Thread(target=task) t.start()
4.自定义:普通版实现threading.local函数的功能
import threading class Local(object): def __init__(self): # 调用父类的__setattr__方法,相当于在父类里面创建self.storage= {} object.__setattr__(self,'storage',{}) def __setattr__(self, key, value): ident = threading.get_ident() # 获取当前线程唯一标识 if ident in self.storage: self.storage[ident][key] = value # 如果ident在storage里面,就将key:value赋值给ident的数组 # {'storage': {98520: {'x1': 0}}} # storage ident key value else: self.storage[ident] = {key:value} def __getattr__(self, item): ident = threading.get_ident() if ident not in self.storage: return return self.storage[ident].get(item) # self.storag[ident] 获取父类的self.storag[ident],因为Local里面没有self.storag字典 local = Local() # 执行父类的__setattr__ def task(arg): local.x1 = arg # 执行Local的__setattr__ print(local.x1) # print(local.__dict__) # { # 'storage': # { # 98520: {'x1': 0}, # 100180: {'x1': 1}, # 99508: {'x1': 2}, # 72148: {'x1': 3}, # 101740: {'x1': 4} # } # } for i in range(5): t = threading.Thread(target=task,args=(i,)) t.start()
# 自定义的方法完全实现了treading.local方法相同的功能
5.自定义:高级版实现threading.local的功能
import threading class Local(object): def __init__(self): object.__setattr__(self,'storage',{}) def __setattr__(self, key, value): ident = threading.get_ident() if ident in self.storage: self.storage[ident][key].append(value) # 使用列表维护成一个栈 else: self.storage[ident] = {key:[value,]} def __getattr__(self, item): ident = threading.get_ident() if ident not in self.storage: return return self.storage[ident][item][-1] # 取列表的最后一个值 local = Local() def task(arg): local.x1 = arg print(local.x1) # print(local.__dict__) 等价于storage的字典 #{ # 'storage': # { # 83880: {'x1': [0]}, # 101040: {'x1': [1]}, # 99688: {'x1': [2]}, # 94888: {'x1': [3]}, # 99760: {'x1': [4]} # } # } for i in range(5): t = threading.Thread(target=task,args=(i,)) t.start() # 在字典的内部维护一个列表,使用列表的append和pop来完成栈的功能 # 取值的时候storage[ident][item][-1] 获取栈顶的值。
# 高级版的比普通版的只是将valve存成了列表
总结
这也是flask实现threading.local功能的简单版代码实现
那么我们为什么要费劲的了解threading.local以及自己实现threading.local的功能那???
因为这是flask的上下文管理的基本,也是实现部分
请看下一篇文章:flask中Localstack和Local对象实现
pass
上帝说要有光,于是便有了光;上帝说要有女人,于是便有了女人!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类