• werkzeug(flask)中的local,localstack,localproxy探究


    1.关于local

    python中有threading local处理方式,在多线程环境中将变量按照线程id区分

    由于协程在Python web中广泛使用,所以threading local不再满足需要

    local中优先使用greenlet协程,其次是线程id,如下所示:

    try:
        from greenlet import getcurrent as get_ident
    except ImportError:
        try:
            from thread import get_ident
        except ImportError:
            from _thread import get_ident

    另外local中定义了一个__release_local__函数,用于清除本协程(线程)下的所有数据:

        def __release_local__(self):
            self.__storage__.pop(self.__ident_func__(), None)

    2 localstack

    localstack相当于在本协程(线程)中将数据以stack的形式存储

    这是通过封装local来实现的

    3 localproxy

    如其名字所示,这是local的代理。

    下面由flask中的context locals来分析

    # context locals
    _request_ctx_stack = LocalStack()
    _app_ctx_stack = LocalStack()
    current_app = LocalProxy(_find_app)
    request = LocalProxy(partial(_lookup_req_object, 'request'))
    session = LocalProxy(partial(_lookup_req_object, 'session'))
    g = LocalProxy(partial(_lookup_app_object, 'g'))

    首先是current_app,我们首先要知道_find_app长啥样:

    def _find_app():
        top = _app_ctx_stack.top
        if top is None:
            raise RuntimeError(_app_ctx_err_msg)
        return top.app

    ok,_app_ctx_stack,这个东西是一个localstack的对象。

    localstack的构造函数里只干了一件事:

    self._local = Local()

    那 _app_ctx_stack.top是什么意思?其实就是取绑定在self._local的stack(一个list)的顶部值:

      @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
    也就是说,我们传入localproxy的是一个callable的函数,当call的时候,返回当前线程中app stack里面顶部元素所绑定的的app
    下面我们需要看localproxy的构造函数了:
        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)

    ok,当我们使用self.__local的时候,实际上使用的是传入的callable object: _find_app

    接着分析request:

    partial(_lookup_req_object, 'request'),意味着当call _lookup_req_object的时候,'request'会作为第一个参数传入。

    那call _lookup_req_object 的时候发生了什么?

    def _lookup_req_object(name):
        top = _request_ctx_stack.top
        if top is None:
            raise RuntimeError(_request_ctx_err_msg)
        return getattr(top, name)

    ok,实际上返回当前线程中request stack里面顶部元素所绑定的的request的属性

    session,g的分析与request同理,只不过前者是在request stack上,后者是在app stack上

     ref: https://www.jianshu.com/p/3f38b777a621

  • 相关阅读:
    python:xlrd模块
    psql:转:会引起全表扫描的10种sql语句
    Linux相关
    面试题
    Siege Web服务器性能压力测试工具
    Nginx+uWSGI+Supervisor配置
    SQLAlchemy
    Virtualenv创建虚拟环境
    算法
    Mac常用快捷键
  • 原文地址:https://www.cnblogs.com/geeklove01/p/8542868.html
Copyright © 2020-2023  润新知