目录
二、Local组件的简单使用 - local对象.变量名 = 赋值
三、实现Local并使其兼容线程和协程 - 参考Flask源码
一、local 简单介绍
python3 - 多线程 - threading 模块(基于win系统)- Thread、Timer 组件
当多个线程修改同一个数据时,将该数据复制多份给每个线程单独使用,即为每个线程开辟一块空间进行数据存储
1-1 不使用local组件存在的弊端
多个线程同时操作同一个全局变量,每次操作都会修改值,存在锁机制。导致每个线程取到的起始数据不相同,导致最后结果输出错误。
# 未使用local from threading import Thread import time test= -1 def task(arg): global test test= arg # 模拟IO操作,用于实现对全局变量的混乱操作 time.sleep(2) print(test) for i in range(10): t = Thread(target=task,args=(i,)) t.start() ''' 9 9 9 9 9 9 9 9 9 9 '''
二、Local组件的简单使用 - local对象.变量名 = 赋值
总结:由Local组件的简单使用可以看出Local操作类似于字典的操作。
from threading import Thread from threading import local import time from threading import get_ident # get_ident用于获取线程、进程ID号 # 初始化local对象 loc= local() def task(arg): # 对象.val = 1/2/3/4/5 loc.value = arg time.sleep(2) print(loc.value) for i in range(10): t = Thread(target=task,args=(i,)) t.start() ''' 3 1 0 2 5 4 7 6 9 8 '''
2-1 自定义字典实现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()
2-2 基于面对对象实现Local
from threading import get_ident,Thread import time class Local(object): storage = {} def set(self, k, v): ident = get_ident() if ident in Local.storage: Local.storage[ident][k] = v else: Local.storage[ident] = {k: v} def get(self, k): ident = get_ident() return Local.storage[ident][k] obj = Local() def task(arg): obj.set('val',arg) v = obj.get('val') print(v) for i in range(10): t = Thread(target=task,args=(i,)) t.start()
2-3 基于魔法方法实现Local
from threading import get_ident,Thread import time class Local(object): storage = {} def __setattr__(self, k, v): ident = get_ident() if ident in Local.storage: Local.storage[ident][k] = v else: Local.storage[ident] = {k: v} def __getattr__(self, k): ident = get_ident() return Local.storage[ident][k] obj = Local() def task(arg): obj.val = arg print(obj.val) for i in range(10): t = Thread(target=task,args=(i,)) t.start()
2-4 基于魔法方法实现单独存储空间的Local
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()
三、实现Local并使其兼容线程和协程 - 参考Flask源码
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()