2013315晚会,千面魅姬,泉州电视台3套
为什么使用自定义 local,而不是 threading.local。这是由内核决定的
1. web 应用在启动之后,是一单线+协成程启动的话,会污染全局变量,无法区分,
2. 使用多线程+协成无法保证,派发请求的工作协程,无法保证同时工作时且分别位于多个线程内,彼此互不影响
所以: werkzeug 给出了自己的解决方案:local 和 localstack
那么问题来了:请求的上下文的私有变量存储在 local 和 localstack 中,那在多任务时,每次调用 from flask import request, g, session , 如何保证获取正确的上下文,而不发生混乱?
在 中
def _lookup_req_object(name): top = _request_ctx_stack.top if top is none: raise runtimeerror('working outside of request context') return getattr(top, name) _request_ctx_stack = localstack() request = localproxy(partial(_lookup_req_object, 'request')) session = localproxy(partial(_lookup_req_object, 'session'))
在 中, localproxy是一个 local or localstack 的一个代理
@implements_bool class localproxy(object): """""" __slots__ = ("__local", "__dict__", "__name__", "__wrapped__") def __init__(self, local, name=none): object.__setattr__(self, "_localproxy__local", local) object.__setattr__(self, "__name__", name) if callable(local) and not hasattr(local, "__release_local__"): # "local" is a callable that is not an instance of local or # localmanager: mark it as a wrapped function. object.__setattr__(self, "__wrapped__", local) def _get_current_object(self): """return the current object. this is useful if you want the real object behind the proxy at a time for performance reasons or because you want to pass the object into a different context. """ if not hasattr(self.__local, "__release_local__"): return self.__local() try: return getattr(self.__local, self.__name__) except attributeerror: raise runtimeerror("no object bound to %s" % self.__name__) def __getattr__(self, name): if name == "__members__": return dir(self._get_current_object()) return getattr(self._get_current_object(), name)
调用 reqeust:动态 request <= 动态的 _request_ctx_stack.top <= localstack() 每次调用产生使用新的实例与方法结合(request)<= loaclstack.call?
是的,每次调用 request,就会新产生一个proxy实例,每次pop, push, top 均是针对 local 的操作,而 local 的属性赋值与获取均是针对 get_ident 获取的!
如:
class local(object): __slots__ = ("__storage__", "__ident_func__") def __init__(self): object.__setattr__(self, "__storage__", {}) object.__setattr__(self, "__ident_func__", get_ident) """""" 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}
perfect!每次新请求来临时,flask 会把上下文存储在 werkzeug local 中,使用时根据线程或者协程id获取
如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复
新手学习Python2和Python3中print不同的用法
Python基于os.environ从windows获取环境变量
网友评论