flask 中的 werkzeug Local,LocalStack 和 LocalProxy 技术应用
什么是 Local
- wsgi 每次请求,会把过程进行抽离无状态话,过程数据存储在本次请求的全局变量中,使用到了Local. Local 作为每次请求的全局命令空间,属于每次请求的私有
- LocalStack 与 Local 相似,在 Local 基础之上使用堆栈方式进行操作,管理
- 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 获取的!
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获取
这样使用有什么好处
- 支持底层协程操作,提高扩展并发效率
- 避免整个应用对请求上下文的管理与传递
- 扩展兼容性perfect,实现了对第三方应用的插拔式扩展
- 可阅读性强,操作使用简单,易上手
flask 中的 werkzeug Local,LocalStack 和 LocalProxy 技术应用的更多相关文章
- 利用Flask中的werkzeug.security模块加密
1.这种加密方式的原理:加密时混入一段"随机"字符串(盐值)再进行哈希加密.即使 密码相同,如果盐值不同,那么哈希值也是不一样的.现在网站开发中主要是运 用这种加密方法. 2.这个 ...
- Flask中的请求上下文和应用上下文
在Flask中处理请求时,应用会生成一个“请求上下文”对象.整个请求的处理过程,都会在这个上下文对象中进行.这保证了请求的处理过程不被干扰.处理请求的具体代码如下: def wsgi_app(self ...
- werkzeug(flask)中的local,localstack,localproxy探究
1.关于local python中有threading local处理方式,在多线程环境中将变量按照线程id区分 由于协程在Python web中广泛使用,所以threading local不再满足需 ...
- Flask之Local、LocalStack和LocalProxy
在我们使用Flask以及Werkzeug框架的过程中,经常会遇到如下三个概念:Local.LocalStack和LocalProxy.尤其在学习Flask的Request Context和App Co ...
- Flask(3)- flask中的CBV、werkzeug+上下文初步解读、偏函数和线程安全
一.flask中的CBV 对比django中的CBV,我们来看一下flask中的CBV怎么实现? from flask import Flask, render_template, url_for, ...
- 04 flask源码剖析之LocalStack和Local对象实现栈的管理
04 LocalStack和Local对象实现栈的管理 目录 04 LocalStack和Local对象实现栈的管理 1.源码入口 1. flask源码关于local的实现 2. flask源码关于l ...
- Flask中全局变量的实现
我们都知道在Flask中g,request,session和request是作为全局对象来提供信息的,既然是全局的又如何保持线程安全呢,接下来我们就看看flask是如何做到这点的.在源码中的ctx.p ...
- 深入flask中的request
缘起 在使用flask的时候一直比较纳闷request是什么原理,他是如何保证多线程情况下对不同请求参数的隔离的. 准备知识 在讲request之前首先需要先理解一下werkzeug.local中的几 ...
- flask中的上下文_请求上下文和应用上下文
前引 在了解flask上下文管理机制之前,先来一波必知必会的知识点. 面向对象双下方法 首先,先来聊一聊面向对象中的一些特殊的双下划线方法,比如__call__.__getattr__系列.__get ...
随机推荐
- Python基础:20类的定制
类中有一些可自定义的特殊方法,它们中的一些有预定义的默认行为,而其它一些则没有,留到需要的时候去实现.这些特殊方法是Python中用来扩充类的强有力的方式.它们可以实现模拟标准类型和重载操作符等.比如 ...
- hdu 2473 Junk-Mail Filter (暴力并查集)
Problem - 2473 为什么标题写的是暴力并查集?因为我的解法跟网上的有所不同,方法暴力很多. 先解释题意,这是一个模拟处理垃圾邮件的问题.垃圾邮件要根据它们的性质进行分类.对于10w个邮件, ...
- oracle函数 ceil(x)
[功能]返回大于等于x的最小整数值 [参数]x,数字型表达式 [返回]数字 [示例] select ceil(3.1),ceil(2.8+1.3),ceil(0) from dual; 返回4,5,0
- pytorch 优化器调参
torch.optim 如何使用optimizer 构建 为每个参数单独设置选项 进行单次优化 optimizer.step() optimizer.step(closure) 算法 如何调整学习率 ...
- g++ 编译单个文件和多个文件
转载:https://www.cnblogs.com/battlescars/p/cpp_linux_gcc.html 1.单个源文件生成可执行程序 下面是一个保存在文件 helloworld.cpp ...
- BERT的通俗理解 预训练模型 微调
1.预训练模型 BERT是一个预训练的模型,那么什么是预训练呢?举例子进行简单的介绍 假设已有A训练集,先用A对网络进行预训练,在A任务上学会网络参数,然后保存以备后用,当来一个新 ...
- HDU 1071
题意:就是求给你一个抛物线的三个点,第一个给定的点是抛物线的顶点,让你求直线p2p3与抛物线的定积分 思路:因为题目条件给了顶点,所以直接用抛物线的顶点式去求. 本弱弱数学太差.还得复习一下公式 #i ...
- Mule自带例子之loanbroker-simple
1 配置效果图 2 配置文件 <?xml version="1.0" encoding="UTF-8"?> <mule xmlns:cxf=& ...
- centOS 重启 php-fpm
ps axo pid,%cpu,%mem,comm |grep php-fpm ps aux | grep php-fpm pkill -9 php-fpm /etc/init.d/php-fpm ...
- H5 移动端获取当前位置
3种方法:1.H5自带的方法,获取经纬度2.通过地图提供的JS.获取位置3.通过微信的API(这个需要公众号 / 小程序) 1.通过H5自带的获取经纬度的方法 优点: 需要引用的资源较少,H5自带的方 ...