flask源码关于local的实现
try: # 协程 from greenlet import getcurrent as get_ident except ImportError: try: from thread import get_ident # 导入get_ident except ImportError: from _thread import get_ident """ __storage__ = { 1111:{"stack":[汪洋] } } """ class Local(object): def __init__(self): # self.__storage__ = {} # self.__ident_func__ = get_ident object.__setattr__(self, "__storage__", {}) object.__setattr__(self, "__ident_func__", get_ident) def __iter__(self): return iter(self.__storage__.items()) def __release_local__(self): self.__storage__.pop(self.__ident_func__(), None) # 由于get_ident是一个方法,当获取到这个对象之后需要加括号才能执行所以self.__ident_func__() def __getattr__(self, name): try: return self.__storage__[self.__ident_func__()][name] except KeyError: raise AttributeError(name) def __setattr__(self, name, value): ident = self.__ident_func__() # 1111 storage = self.__storage__ try: storage[ident][name] = value except KeyError: storage[ident] = {name: value} def __delattr__(self, name): try: del self.__storage__[self.__ident_func__()][name] except KeyError: raise AttributeError(name) class LocalStack(object): def __init__(self): self._local = Local() def push(self, obj): """Pushes a new item to the stack""" # self._local.stack == getattr # rv = None rv = getattr(self._local, "stack", None) if rv is None: self._local.stack = rv = [] rv.append(obj) return rv def pop(self): stack = getattr(self._local, "stack", None) if stack is None: return None elif len(stack) == 1: # release_local(self._local) # del __storage__[1111] return stack[-1] else: return stack.pop() @property def top(self): try: return self._local.stack[-1] except (AttributeError, IndexError): return None obj = LocalStack() obj.push('汪洋') obj.push('成说') print(obj.top) obj.pop() obj.pop()
总结:
在flask中有个local类,他和threading.local的功能一样,为每个线程开辟空间进行存取数据,他们两个的内部实现机制,内部维护一个字典,以线程(协程)ID为key,进行数据隔离,如: __storage__ = { 1211:{'k1':123} } obj = Local() obj.k1 = 123 在flask中还有一个LocalStack的类,他内部会依赖local对象,local对象负责存储数据,localstack对象用于将local中的值维护成一个栈。 __storage__ = { 1211:{'stack':['k1',]} } obj= LocalStack() obj.push('k1') obj.top obj.pop()
7.flask源码中总共有2个localstack对象
# context locals __storage__ = { 1111:{'stack':[RequestContext(reqeust,session),]}, 1123:{'stack':[RequestContext(reqeust,session),]}, } _request_ctx_stack = LocalStack() __storage__ = { 1111:{'stack':[AppContenxt(app,g),]} 1123:{'stack':[AppContenxt(app,g),]}, } _app_ctx_stack = LocalStack()
_request_ctx_stack.push('小魔方') _app_ctx_stack.push('大魔方')
- 上下文管理
- 请求上下文管理
- 应用上下文管理
解析
1. 首先说请求上下文管理的设计思路: * 当开启多线程或者协程去执行这个程序的时候,就需要对每个访问对象包装自己的数据,这样就不会发生数据的冲突,那么要怎么才能规避这个问题呢?? * 利用threading.local的知识,根据相似的实现原理,设计这个上下文管理机制; * 首先写一个Local类,这个类中封装两个属性一个的属性值是一个空的字典,这个空字典的设计是这样的:字典中的键是当先执行的线程或者协程的id值,然后值是一个空的列表; *另一个是get_ident方法名,这个方法是获取可以获取到线程或者协程的id;这个的内部是将协程的模块名改成:get_ident了,所以你如果开的是线程就获取线程的id,如果是协程就获取协程的id; * 然后就是这个类中的实现方法了,有一个__setattr__方法,这个方法的作用主要是增加给__storage__这个字典中增加值的,__getattr__这个方法时获取这当前这线程或者协程值对应的id去__storage__获取对应的id的那个列表; * 还有一个清空当前线程或者协程保存的数据__release_local__,