フラスココンテキスト管理システムのプロセス(ソースコード分析)

フラスコ要求コンテキスト管理

部分関数

  • この部分的な実施形態を使用すると、新しい関数を生成することができます

    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フラスコ上記のリクエスト

  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)
  1. 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
  2. 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)
  3. オブジェクトプッシュ方式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を返します
  4. ローカルオブジェクトは辞書で得られた値を初期化されます

    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
  5. プッシュ方法を実行する_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

  1. インポート要求は要求に、開始しました

    #此时request是一个函数包裹一个偏函数   LocalProxy()是一个代理
    #当前的request是一个LocalProxy()  request.method  执行__getattr__方法
    request = LocalProxy(
        partial(_lookup_req_object, 'request')   #return request对象
    )
  2. _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)ません。
  3. このレイヤオブジェクトを実行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偏函数
  4. 現在の要求が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つの段階に分けることができます。

  1. リクエストの上- >
    リクエストが来たとき、まず最初に、スレッドに対応するスペース(スペースを開くには、サーバーのリクエストに応じて現在のスレッドを取ることです、具体的には、スタック・ストレージ・CTX(リクエスト/セッション)に対応するリストが含まれている必要があります- >:RequestContextのクラスにカプセル化された要求、セッション
    ローカルおよびAppContextをクラスにアプリ、G AppContextをクラスにカプセル化され、そしてRequestContextのによりLocalStack
    ローカルクラスで、辞書のキーとしてスレッドID番号、
  2. 次の要求
    localproxyによって--->一部の機能---> localstack --->ローカル値
  3. 「要求応答」: - >データコンテキスト管理をクリアする
    (第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 等

おすすめ

転載: www.cnblogs.com/bigox/p/11652859.html