flask 中的 werkzeug Local,LocalStack 和 LocalProxy 技术应用

什么是 Local

  1. wsgi 每次请求,会把过程进行抽离无状态话,过程数据存储在本次请求的全局变量中,使用到了Local. Local 作为每次请求的全局命令空间,属于每次请求的私有
  2. LocalStack 与 Local 相似,在 Local 基础之上使用堆栈方式进行操作,管理
  3. LocalProxy 代理类,代理 Local 或 LocalStack 实例

为什么使用 Local

  为什么使用自定义 Local,而不是 threading.local。这是由内核决定的

    1. web 应用在启动之后,是一单线+协成程启动的话,会污染全局变量,无法区分,

    2. 使用多线程+协成无法保证,派发请求的工作协程,无法保证同时工作时且分别位于多个线程内,彼此互不影响

所以: werkzeug 给出了自己的解决方案:Local 和 LocalStack

为什么使用 LocalProxy

  那么问题来了:请求的上下文的私有变量存储在 Local 和 LocalStack 中,那在多任务时,每次调用 from flask import request, g, session , 如何保证获取正确的上下文,而不发生混乱?

在 flask.globals.py 中

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‘))

在 werkzeug.local.py 中, 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 获取的!

如:werkzeug.local.Local.py

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获取

这样使用有什么好处

  1. 支持底层协程操作,提高扩展并发效率
  2. 避免整个应用对请求上下文的管理与传递
  3. 扩展兼容性perfect,实现了对第三方应用的插拔式扩展
  4. 可阅读性强,操作使用简单,易上手

原文地址:https://www.cnblogs.com/spaceapp/p/12157940.html

时间: 2024-08-29 09:50:15

flask 中的 werkzeug Local,LocalStack 和 LocalProxy 技术应用的相关文章

利用Flask中的werkzeug.security模块加密

1.这种加密方式的原理:加密时混入一段"随机"字符串(盐值)再进行哈希加密.即使 密码相同,如果盐值不同,那么哈希值也是不一样的.现在网站开发中主要是运 用这种加密方法. 2.这个模块主要是用到了两个函数: 密码生成函数:generate_password_hash: 密码验证函数:check_password_hash: 3.密码生成函数:generate_password_hash 函数定义 werkzeug.security.generate_password_hash(pass

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 Im

Flask中全局变量的实现

我们都知道在Flask中g,request,session和request是作为全局对象来提供信息的,既然是全局的又如何保持线程安全呢,接下来我们就看看flask是如何做到这点的.在源码中的ctx.py中有AppContext和RequestContext两个类,他们分别管理应用上下文和请求上下文.两者的实现也差不多,这里我们看看AppContext的实现 class AppContext(object): """The application context binds a

Flask中的请求上下文和应用上下文

本文章粘贴自 https://blog.tonyseek.com/post/the-context-mechanism-of-flask/ 用过 Flask 做 Web 开发的同学应该不会不记得 App Context 和 Request Context 这两个名字--这两个 Context 算是 Flask 中比较特色的设计.[1] 从一个 Flask App 读入配置并启动开始,就进入了 App Context,在其中我们可以访问配置文件.打开资源文件.通过路由规则反向构造 URL.[2] 

flask项目深度研究之localstack

重启博客,记录一些零散的知识和复习学习过的知识 今天记录的是关于localstack的一些知识,首先需要讲到python原生的threadlocal a = 10 import threading def test(): print(a) thread = threading.Thread(target=test) thread.start() thread.join() 如上,有一个变量a,若线程相对其进行操作,可以将其作为参数传进去,如果要对其进行修改,则需要加锁,操作起来很麻烦,为了解决这

Werkzeug之LocalStack源码解析

Werkzeug之LocalStack源码解析 原博文地址 http://liuyajing.coding.me/blogs/python/2018/werkzeug-localstack/ 一.引入 最近在阅读 Flask 的源码,遇到三个概念:Local . LocalStack 和 LocalProxy ,本文主要就针对 LocalStack 概念及其源码进行原理剖析. 二.原理 这个类类似于:class:Local,但是在 storage[ident] 中存放的是一个 key 为 sta

Flask中处理依赖的技巧

Flask应用中通常会用工厂模式 来创建应用对象,这样方便配置和测试.现在我们就用实例来学习Flask的处理依赖 应用代码 # app/__init__.pyfrom flask import Flaskfrom flask_xxxext import Xxxfrom flask_yyyext import Yyy# ... 一些flask拓展xx = Xxx()yy = Yyy() def create_app(config=None): app = Flask(__name__) xx.in

整合Flask中的目录结构

一.SQLAlchemy-Utils 由于sqlalchemy中没有提供choice方法,所以借助SQLAlchemy-Utils组件提供的choice方法 import datetime from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String, Text, ForeignK

用flask开发个人博客(4)—— flask中4种全局变量

https://blog.csdn.net/hyman_c/article/details/53512109 一  current_app current_app代表当前的flask程序实例,使用时需要flask的程序上下文激活,我们以本专栏第一篇文章中写的test.py为例介绍下它的用法: 1.1 激活程序上下文 [python] view plain copy >>> from test import app >>> from flask import curren