Flask上下文管理
-threading.local对象,用于为每个线程开辟一块空间来保存它独有的值。
-源码(request)
-情况一:单进程单线程,基于全局变量做。
-情况二:单进程多线程,threading.local对象。
-情况三:单进程单线程(多协程),threading.lcoal对象做不到。
-建议:
-以后不支持协程:就用threading.local对象
-支持协程:自定义类似threading.local对象
线程
通过threading.local()保护线程数据安全
1 import threading 2 local_values = threading.local() 3 4 ''' 5 local_values = threading.local()就是起到一个锁的作用,每个线程都可以对threading.local对象进行读写,且互相不干扰。 6 用于为每个线程开辟一块空间来保存它独有的值。 7 ''' 8 def func(num): 9 local_values.name=num 10 import time 11 time.sleep(1) 12 print(local_values.name,threading.current_thread().name) 13 14 for i in range(10): 15 th = threading.Thread(target=func,args=(i,),name="线程是%s"%i) 16 th.start()
一个简单的自定义方法实现threading.local功能:
线程
1 import threading 2 from _thread import get_ident 3 '''获取线程唯一标示''' 4 class LOCAL(object): 5 ''' 6 通过自定义的方式实现threadlocal的功能 7 初始化的时候定义一个字典以及线程唯一标示 8 然后通过set设置k,v,再用get取值 9 ''' 10 def __init__(self): 11 self.storage = {} 12 self.get_ident = get_ident 13 def set(self,k,v): 14 ident = self.get_ident() 15 origin = self.storage.get(ident) 16 if not origin: 17 origin = {k:v} 18 else: 19 origin[k] = v 20 self.storage[ident] = origin 21 def get(self,k): 22 ident = self.get_ident() 23 origin = self.storage.get(ident) 24 if not origin: 25 return None 26 return origin.get(k,None) 27 28 local_values = LOCAL() 29 def task(num): 30 local_values.set('name',num) 31 import time 32 time.sleep(1) 33 print(local_values.get('name'), threading.current_thread().name) 34 for i in range(10): 35 th = threading.Thread(target=task,args=(i,),name="线程是%s"%i) 36 th.start()
通过安装gevent,用getcurrent的方式获取协程的唯一标示:
以下是实现协程的单独资源管理
1 import threading 2 from greenlet import getcurrent as get_ident 3 '''获取协程唯一标示,需要安装gevent,同时自动安装greenlet,通过 4 from greenlet import getcurrent 模块判断协程唯一标示,其他代码不变''' 5 class LOCAL(object): 6 ''' 7 通过自定义的方式实现threadlocal的功能 8 初始化的时候定义一个字典以及线程唯一标示 9 然后通过set设置k,v,再用get取值 10 ''' 11 def __init__(self): 12 self.storage = {} 13 self.get_ident = get_ident 14 def set(self,k,v): 15 ident = self.get_ident() 16 origin = self.storage.get(ident) 17 if not origin: 18 origin = {k:v} 19 else: 20 origin[k] = v 21 self.storage[ident] = origin 22 def get(self,k): 23 ident = self.get_ident() 24 origin = self.storage.get(ident) 25 if not origin: 26 return None 27 return origin.get(k,None) 28 29 local_values = LOCAL() 30 def task(num): 31 local_values.set('name',num) 32 import time 33 time.sleep(1) 34 print(local_values.get('name'), threading.current_thread().name) 35 for i in range(10): 36 th = threading.Thread(target=task,args=(i,),name="线程是%s"%i) 37 th.start()
面向对象知识点补充
关于__setattr__的使用以及常见问题:
1 #扩展内容,__setattr__ 2 class Foo(object): 3 def set(self,k,v): 4 pass 5 def __setattr__(self, key, value): 6 print(key,value) 7 pass 8 9 obj = Foo() 10 obj.set('x',123) 11 obj.x = 123 #用__setattr__比set函数要方便许多 12 13 #__setattr__方法常见的坑 14 15 class Foo(object): 16 def __init__(self): 17 self.storage = {} 18 def __setattr__(self, key, value): 19 self.storage={'k1':'v1'} 20 print(key,value) 21 def __getattr__(self, item): 22 print(item) 23 24 25 obj = Foo() 26 obj.x = 123 27 ''' 28 当初始化的时候,self.storage,对象调用storage就会自动执行__setattr__方法, 29 然后__setattr__方法里面又是对象调用属性,就会再执行setattr,这样就是无限递归了。 30 为了避免这个问题需要用下面这种方式实现: 31 ''' 32 class Foo(object): 33 def __init__(self): 34 object.__setattr__(self,'storage',{}) 35 36 def __setattr__(self, key, value): 37 self.storage={'k1':'v1'} 38 print(key,value) 39 40 def __getattr__(self, item): 41 print(item) 42 return "sdf" 43 obj = Foo() 44 #注意如果obj.x = 123就会触发__setattr__方法,还是会出现递归的问题。
以下为参考源码实现的方式:
1 #源码的实现方式: 2 import threading 3 try: 4 from greenlet import getcurrent as get_ident # 协程 5 except ImportError: 6 try: 7 from thread import get_ident 8 except ImportError: 9 from _thread import get_ident # 线程 10 11 12 class Local(object): 13 14 def __init__(self): 15 object.__setattr__(self, '__storage__', {}) 16 object.__setattr__(self, '__ident_func__', get_ident) 17 18 19 def __getattr__(self, name): 20 try: 21 return self.__storage__[self.__ident_func__()][name] 22 except KeyError: 23 raise AttributeError(name) 24 25 def __setattr__(self, name, value): 26 ident = self.__ident_func__() 27 storage = self.__storage__ 28 try: 29 storage[ident][name] = value 30 except KeyError: 31 storage[ident] = {name: value} 32 33 def __delattr__(self, name): 34 try: 35 del self.__storage__[self.__ident_func__()][name] 36 except KeyError: 37 raise AttributeError(name) 38 39 40 local_values = Local() 41 42 43 def task(num): 44 local_values.name = num 45 import time 46 time.sleep(1) 47 print(local_values.name, threading.current_thread().name) 48 49 50 for i in range(20): 51 th = threading.Thread(target=task, args=(i,),name='线程%s' % i) 52 th.start()