フラスコ要求コンテキスト管理
部分関数
この部分的な実施形態を使用すると、新しい関数を生成することができます
from functools import partial def mod( n, m ): return n % m mod_by_100 = partial( mod, 100 ) # 100传给n print mod( 100, 7 ) # 2 print mod_by_100( 7 ) # 2
2スレッドセーフ
import time
from threading import local
class Foo(local):
# 继承local,保证线程安全,也保证了处理速度,threading.local()这个方法的特点用来保存一个全局变量,但是这个全局变量只有在当前线程才能访问,
num = 0
foo = Foo()
def add(i):
foo.num =i
time.sleep(0.5)
print(foo.num)
from threading import Thread
for i in range(20):
task = Thread(target=add,args=(i,))
task.start()
要求コンテキスト3
3.1フラスコ上記のリクエスト
- リクエストが来た場合、アプリは()、フラスコを対象アプリをインスタンス化**行っ__call __ **
def __call__(self, environ, start_response):
"""The WSGI server calls the Flask application object as the
WSGI application. This calls :meth:`wsgi_app` which can be
wrapped to applying middleware."""
return self.wsgi_app(environ, start_response)
Wsgi_appを得るために行わ目標CTXのRequestContextの(要求を、セッションをパッケージ)
ctx = self.request_context(environ)
class RequestContext(object): #此时的self是RequestContext对象 -->ctx 中封装了request/session def __init__(self, app, environ, request=None): self.app = app #app = Flask对象 if request is None: #请求的原始信息通过request_class后此时request已经存在,request.methods等 request = app.request_class(environ) self.request = request self.url_adapter = app.create_url_adapter(self.request) self.flashes = None self.session = None
CTX実行ctx.push():
ctx = self.request_context(environ) error = None try: try: ctx.push() response = self.full_dispatch_request() except Exception as e: error = e response = self.handle_exception(e)
オブジェクトプッシュ方式RequestContextの
def push(self): # _request_ctx_stack = LocalStack()一个LocalStack对象 # _request_ctx_stack._local = LocalStack()._loacl = {"__storage__":{},"__ident_func__":get_ident} top = _request_ctx_stack.top #top =None if top is not None and top.preserved: top.pop(top._preserved_exc)
- _ Request_ctx_stackがあるLocalStackの、オブジェクトLocalStack())ローカル._すなわちローカルローカルオブジェクト(あります
class LocalStack(object): def __init__(self): self._local = Local() #self._loacl = {"__storage__":{},"__ident_func__":get_ident}
- _request_ctx_stackトップの方法は、(半時間疑問に思っ叫び、ない涙、この方法で、)Noneを返します
ローカルオブジェクトは辞書で得られた値を初期化されます
class Local(object): #限定键槽,当前只能由两个属性值__storage__,__ident_func__ __slots__ = ('__storage__', '__ident_func__') def __init__(self): object.__setattr__(self, '__storage__', {}) object.__setattr__(self, '__ident_func__', get_ident) # {"__storage__":{},"__ident_func__":get_ident} #此时get_dient 是个没有执行的函数,内存地址
- トップ方法_request_ctx_stack(第2のだまされない)Noneを返します
@property def top(self): """The topmost item on the stack. If the stack is empty, `None` is returned. """ try: # self._local 即Local对象调用__getattr__方法 #在下文时候Local对象{"__storage__":{8080:{stack:rv=[ctx->request/session]}},"__ident_func__":get_ident} # [ctx->request/session] return self._local.stack[-1] #得到ctx对象 except (AttributeError, IndexError): return None
プッシュ方法を実行する_request_ctx_stackオブジェクト
_request_ctx_stack.push(self) #当前的self为ctx
def push(self, obj): #此时的self是LocalStack对象, obj为ctx """Pushes a new item to the stack""" # self._local = {"__storage__":{},"__ident_func__":get_ident} #找不到返回值是None rv = getattr(self._local, 'stack', None) if rv is None: #由于.stack后面有等号,执行的时候Local()对象的__setattr__方法 #实际上是地址的赋值,此时stack和rv都指向空列表 self._local.stack = rv = [] #{"__storage__":{8080:{stack:rv=[]}},"__ident_func__":get_ident} rv.append(obj) # {"__storage__":{8080:{stack:rv=[ctx->request/session]}},"__ident_func__":get_ident} # 应用上下文时候{"__storage__":{8080:{stack:rv=[app_ctx->(app/g)]}},"__ident_func__":get_ident} return rv #rv=[ctx->request/session]
def __setattr__(self, name, value): #name=stack value=rv=[] #self是Local对象 {"__storage__":{},"__ident_func__":get_ident} ident = self.__ident_func__() #执行get_ident函数获取当前线程id 8080 storage = self.__storage__ #storge ={8080:{stack:rv=[]}} try: storage[ident][name] = value except KeyError: storage[ident] = {name: value} #storage={} # {"__storage__":{8080:{stack:rv=[]}},"__ident_func__":get_ident}
- プッシュを要求する方法を実行する上記終了します。
#当请求进来,第一件事就是要把当前这个请求在我服务器上的线程开辟一个空间(线程对应的空间,必须含有stack对应一个列表存放ctx(request/session) # {"__storage__":{8080:{stack:rv=[ctx->request/session]}},"__ident_func__":get_ident}
以下の要求3.3.2Flask
インポート要求は要求に、開始しました
#此时request是一个函数包裹一个偏函数 LocalProxy()是一个代理 #当前的request是一个LocalProxy() request.method 执行__getattr__方法 request = LocalProxy( partial(_lookup_req_object, 'request') #return request对象 )
_lookup_req_objectに渡された要求の中の部分的な機能:この時点ではリクエストオブジェクトを与えるために、
def _lookup_req_object(name): # _request_ctx_stack是LocalStack对象 top = _request_ctx_stack.top #下文[ctx->request/session] if top is None: raise RuntimeError(_request_ctx_err_msg) #此时的name是request,从ctx对象中找出request对象 return getattr(top, name)
...
@property def top(self): """The topmost item on the stack. If the stack is empty, `None` is returned. """ try: # self._local 即Local对象调用__getattr__方法 #在下文时候Local对象{"__storage__":{8080:{stack:rv=[ctx->request/session]}},"__ident_func__":get_ident} # [ctx->request/session] return self._local.stack[-1] #得到ctx对象 except (AttributeError, IndexError): return None
- トップケースのいずれも既に現在値(0.0)ません。
このレイヤオブジェクトを実行reauestを与える部分(_lookup_req_object、「要求」)はLocalProxyの一部の機能に渡されます
@implements_bool class LocalProxy(object): __slots__ = ('__local', '__dict__', '__name__', '__wrapped__') def __init__(self, local, name=None): #local是request偏函数 object.__setattr__(self, '_LocalProxy__local', local) #__local = request偏函数 object.__setattr__(self, '__name__', name) #当前偏函数可以执行而且判断loacl中是否有 __release_local__ ==>这句话成立 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) #__warpped__还是local偏函数
現在の要求がLocalProxyで行わrequest.method __getattr__ LocalProxy()メソッドであります
def __getattr__(self, name): # name是method(举例) if name == '__members__': return dir(self._get_current_object()) #此时self._get_current_object()是经过_local 执行后得到的request对象,从request对象中去取出method return getattr(self._get_current_object(), name)
...
def _get_current_object(self): #self._local是偏函数 if not hasattr(self.__local, '__release_local__'): #执行偏函数,返回request对象 return self.__local() try: return getattr(self.__local, self.__name__) except AttributeError: raise RuntimeError('no object bound to %s' % self.__name__)
3.3.3まとめ
この光の中で見ると、falskコンテキスト管理には3つの段階に分けることができます。
- リクエストの上- >
リクエストが来たとき、まず最初に、スレッドに対応するスペース(スペースを開くには、サーバーのリクエストに応じて現在のスレッドを取ることです、具体的には、スタック・ストレージ・CTX(リクエスト/セッション)に対応するリストが含まれている必要があります- >:RequestContextのクラスにカプセル化された要求、セッション
ローカルおよびAppContextをクラスにアプリ、G AppContextをクラスにカプセル化され、そしてRequestContextのによりLocalStack
ローカルクラスで、辞書のキーとしてスレッドID番号、 - 次の要求
localproxyによって--->一部の機能---> localstack --->ローカル値 - 「要求応答」: - >データコンテキスト管理をクリアする
(第save.sessionを行う)、各(POPを実行する)、ローカルクリアランスデータ
ソースコードの詳細な表情
3.4アプリケーション・コンテキスト
Wsgi_app実行方法
#ctx为一个RequestContext的对象,参数为environ ctx = self.request_context(environ) error = None try: try: ctx.push() response = self.full_dispatch_request() except Exception as e: error = e response = self.handle_exception(e)
トップがNoneのとき、プッシュ方式を実行し、_app_ctx_stackもLocalStckオブジェクトが初期化されています
def push(self): app_ctx = _app_ctx_stack.top #app_ctx = None if app_ctx is None or app_ctx.app != self.app: app_ctx = self.app.app_context() #app_context是AppContext对象 与RequestContenx一样,知识序列化出app和g app_ctx.push() # 应用上文时候{"__storage__":{8080:{stack:rv=[app_ctx->(app/g)]}},"__ident_func__":get_ident} self._implicit_app_ctx_stack.append(app_ctx) else: self._implicit_app_ctx_stack.append(None)
- そして、** _ ** app_ctx_stack.push app_ctx.pushを実行します
def push(self): """Binds the app context to the current context.""" self._refcnt += 1 if hasattr(sys, 'exc_clear'): sys.exc_clear() #将AppContext存在LocalStack对象中 _app_ctx_stack.push(self) appcontext_pushed.send(self.app)
def push(self, obj): #此时的self是LocalStack对象, obj为ctx """Pushes a new item to the stack""" # self._local = {"__storage__":{},"__ident_func__":get_ident} #找不到返回值是None rv = getattr(self._local, 'stack', None) if rv is None: #由于.stack后面有等号,执行的时候Local()对象的__setattr__方法 #实际上是地址的赋值,此时stack和rv都指向改空列表 self._local.stack = rv = [] #{"__storage__":{8080:{stack:rv=[]}},"__ident_func__":get_ident} rv.append(obj) # {"__storage__":{8080:{stack:rv=[ctx->request/session]}},"__ident_func__":get_ident} # 应用上下文时候{"__storage__":{8080:{stack:rv=[app_ctx->(app/g)]}},"__ident_func__":get_ident} return rv #rv=[ctx->request/session]
global.pyに:これは、プッシュ完了し、上記のアプリケーションを終了し、アプリケーションは、さらに以下のオフラインスクリプトを使用しました
def _find_app():
top = _app_ctx_stack.top #得到app_ctx(app / g)
if top is None:
raise RuntimeError(_app_ctx_err_msg)
return top.app #返回一个app即flask对象 只不过此时的flask对象 是公共的,与初始化的相同
# 但是是独立出来已经被配置好的Flask对象
# LocalStack是 针对当前这个线程对独立的Flask_app进行修改, 不影响现在运行的app =>离线脚本
#但是这个app 在请求结束后会从LocalStack中通过 __delattr__ 删除
# context locals
_request_ctx_stack = LocalStack() #LocalStark = self._loacl = {"__storage__":{},"__ident_func__":get_ident}
_app_ctx_stack = LocalStack()
current_app = LocalProxy(_find_app) # current_app可以点 .run | .route 等