一、介绍
threading.local的作用:
多个线程修改同一个数据,复制多份变量给每个线程用,为每个线程开辟一块空间进行数据的存储,而每块空间内的数据也不会错乱。
二、不使用threading.local会导致数据错乱
# 不用local from threading import Thread import time lqz = -1 def task(arg): global lqz lqz = arg # time.sleep(2) print(lqz) for i in range(10): t = Thread(target=task,args=(i,)) t.start()
三、使用threading.local
from threading import Thread from threading import local import time from threading import get_ident # 特殊的对象 lqz = local() def task(arg): # 对象.val = 1/2/3/4/5 lqz.value = arg time.sleep(2) print(lqz.value) for i in range(10): t = Thread(target=task,args=(i,)) t.start()
四、通过字典自定义threading.local(函数)
from threading import get_ident,Thread import time storage = {} def set(k,v): ident = get_ident() if ident in storage: storage[ident][k] = v else: storage[ident] = {k:v} def get(k): ident = get_ident() return storage[ident][k] def task(arg): set('val',arg) v = get('val') print(v) for i in range(10): t = Thread(target=task,args=(i,)) t.start()
五、每个对象有自己的存储空间(字典)
from threading import get_ident,Thread import time class Local(object): def __init__(self): object.__setattr__(self,'storage',{}) def __setattr__(self, k, v): ident = get_ident() if ident in self.storage: self.storage[ident][k] = v else: self.storage[ident] = {k: v} def __getattr__(self, k): ident = get_ident() return self.storage[ident][k] obj = Local() def task(arg): obj.val = arg obj.xxx = arg print(obj.val) for i in range(10): t = Thread(target=task,args=(i,)) t.start()
六、兼容线程和协程
try: from greenlet import getcurrent as get_ident except Exception as e: from threading import get_ident from threading import Thread import time class Local(object): def __init__(self): object.__setattr__(self,'storage',{}) def __setattr__(self, k, v): ident = get_ident() if ident in self.storage: self.storage[ident][k] = v else: self.storage[ident] = {k: v} def __getattr__(self, k): ident = get_ident() return self.storage[ident][k] obj = Local() def task(arg): obj.val = arg obj.xxx = arg print(obj.val) for i in range(10): t = Thread(target=task,args=(i,)) t.start()