flask的request和session设置方式比较新颖,如果没有这种方式,那么就只能通过参数的传递。
flask是如何做的呢?
1. 本地线程,保证即使是多个线程,自己的值也是互相隔离。
import threading
local_values = threading.local()
def func(num):
local_values.name = num
import time
time.sleep(1)
print(local_values.name,threading.current_thread().name)
for i in range(20):
th = threading.Thread(target=func,args=(i,),name='线程%s' %i)
th.start()
2. 上下文原理
from functools import partial
from flask.globals import LocalStack, LocalProxy
ls = LocalStack()
class RequestContext(object):
def __init__(self, environ):
self.request = environ
def _lookup_req_object(name):
top = ls.top
if top is None:
raise RuntimeError(ls)
return getattr(top, name)
session = LocalProxy(partial(_lookup_req_object, 'request'))
ls.push(RequestContext('c1')) # 当请求进来时,放入
print(session) # 视图函数使用
print(session) # 视图函数使用
ls.pop() # 请求结束pop
ls.push(RequestContext('c2'))
print(session)
ls.push(RequestContext('c3'))
print(session)
3. Flask内部实现
from greenlet import getcurrent as get_ident
def release_local(local):
local.__release_local__()
class Local(object):
__slots__ = ('__storage__', '__ident_func__')
def __init__(self):
# self.__storage__ = {}
# self.__ident_func__ = get_ident
object.__setattr__(self, '__storage__', {})
object.__setattr__(self, '__ident_func__', get_ident)
def __release_local__(self):
self.__storage__.pop(self.__ident_func__(), None)
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__()
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 __release_local__(self):
self._local.__release_local__()
def push(self, obj):
"""Pushes a new item to the stack"""
rv = getattr(self._local, 'stack', None)
if rv is None:
self._local.stack = rv = []
rv.append(obj)
return rv
def pop(self):
"""Removes the topmost item from the stack, will return the
old value or `None` if the stack was already empty.
"""
stack = getattr(self._local, 'stack', None)
if stack is None:
return None
elif len(stack) == 1:
release_local(self._local)
return stack[-1]
else:
return stack.pop()
@property
def top(self):
"""The topmost item on the stack. If the stack is empty,
`None` is returned.
"""
try:
return self._local.stack[-1]
except (AttributeError, IndexError):
return None
stc = LocalStack()
stc.push(123)
v = stc.pop()
print(v)
注意:
情况一:单进程单线程,基于全局变量做。
情况二:单进程多线程,threading.loacl对象
情况三:单进程多线程(多个协程),threading.local对象做不到
决定:
-以后不支持协程:threading.local对象。
-支持:自定义类似threading.local对象(支持协程)
PS:
a.
object.__setattr__(self, 'storage', {})
self.storage = {}
b.
对象.xx
def __setattr__(self, key, value):
print(key,value)