threading.local
1. 引子
- 假如,开了十个线程并且做同样的一件事,他们需要带着自己的数据进来,完成事情后带着自己的数据出去。如果是并发,同时进来,他们的数据就会混乱
- 一般情况,我们加锁就可以了,一个人先进来,先加锁,另一个人过来看到加锁了,就在外面等,等里面的人出来,自己进去加锁,这样就不会出现数据混乱的问题
- 另一种解决方法就是使用 threading.local() 来解决
2. 介绍
- threading.local 会根据线程id为每一个线程创建一块内存空间(即:每一个线程都有一块独立的内存空间进行数据的存储)
- threading.local 只能为线程开辟空间
3. 作用
- 为每一个线程创建一个独立的内存空间,使得线程对自己的内存中的数据进行操作,实现了线程与线程之间的数据隔离
4. 锁 和 threading.local 的区别
- 锁: 是为了让多个线程修改同一份数据
- threading.local: 为每一个线程创建一块内存空间保存各自的数据
5. 引子的例子
import threading
v = 0
def task(i):
global v
v = i
print(v) # 打印结果: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
for i in range(10):
t = threading.Thread(target=task, args=[i]) # 开启10个线程执行task函数
t.start()
- 此时上面的打印结果看不出任何的问题是因为执行的速度太快了,如果执行速度太快,那么它们取到的值有可能是不一样的
- 只要在打印结果之前执行以下 time.sleep 就可以看到效果了
import threading
import time
v = 0
def task(i):
global v
v = i
time.sleep(2)
print(v) # 打印结果: 9, 9, 9, 9, 9, 9, 9, 9, 9, 9
for i in range(10):
t = threading.Thread(target=task, args=[i]) # 开启10个线程执行task函数
t.start()
6. threading.local 的使用
- 使用 threading.local 解决引子的问题
import threading
import time
from threading import local
local_obj = local() # 实例化local对象
def task(i):
local_obj.abc = i # 将值赋值给local对象上的自定义属性上
time.sleep(2)
print(local_obj.abc) # 打印结果: 0, 3, 2, 4, 5, 1, 9, 6, 8, 7 -> 没有按照顺序打印是因为线程的调用顺序是由CPU来决定的
for i in range(10):
t = threading.Thread(target=task, args=[i]) # 开启10个线程执行task函数
t.start()
7. 自定义 threading.local 的功能
- 函数写法
- 思路: 将 线程唯一标识 作为key,所要保存的值作为 value,存储在字典中
import threading # 线程模块
import time
DIC = {}
"""
DIC = {
5104: {'xxx': 2},
14432: {'xxx': 4},
13940: {'xxx': 7}
……
}
"""
def task(i):
get_ident = threading.get_ident() # 获取线程的唯一标识
if get_ident in DIC:
DIC[get_ident]['xxx'] = i
else:
DIC[get_ident] = {'xxx': i}
time.sleep(2)
print(DIC[get_ident]['xxx']) # 打印结果: 0, 3, 2, 4, 5, 1, 9, 6, 8, 7 -> 没有按照顺序打印是因为线程的调用顺序是由CPU来决定的
for i in range(10):
t = threading.Thread(target=task, args=[i])
t.start()
- 类写法
- 自定义一个类似于 threading.local 的类,且在这基础上添加了支持协程的功能
- 思路: 将 线程唯一标识 或 协程唯一标识 作为key,所要保存的值作为 value,存储在字典中
import threading # 线程模块
import time
# 创建一个类似于 threading.local 的类
class Local(object):
DIC = {}
"""
DIC = {
5104: {'xxx': 2},
14432: {'xxx': 4},
13940: {'xxx': 7}
……
}
"""
# 获取线程或协程的唯一标识
def get_ident(self):
# 如果有协程就优先使用协程,如果没有就使用线程
try:
import greenlet # 因为 greenlet 是第三方模块
get_ident = greenlet.getcurrent # 获取协程的唯一标识(其实是一个函数)
except Exception as e:
get_ident = threading.get_ident() # 获取线程的唯一标识
return get_ident
# 获取值
def __getattr__(self, item):
ident = self.get_ident()
if ident in self.DIC:
return self.DIC[ident].get(item)
# 设置值
def __setattr__(self, key, value):
ident = self.get_ident()
if ident in self.DIC:
self.DIC[ident][key] = value
else:
self.DIC[ident] = {key: value}
local_obj = Local() # 实例化local对象
def task(i):
local_obj.abc = i
time.sleep(2)
print(local_obj.abc) # 打印结果: 0, 3, 2, 4, 5, 1, 9, 6, 8, 7 -> 没有按照顺序打印是因为线程的调用顺序是由CPU来决定的
for i in range(10):
t = threading.Thread(target=task, args=[i])
t.start()
Flask的上下文管理机制的介绍
1. 介绍
- Flask的上下文管理机制类似于 threading.local
- Flask的上下文管理机制的写法类似于 threading.local 章节中的 自定义 threading.local 的功能 -> 类写法
- 根据线程或协程的唯一标识为每一个线程或协程创建一块内存空间(即:每一个线程或协程都有一块独立的内存空间进行数据的存储)
- Flask的上下文管理机制可以为线程或协程开辟空间
- 通俗理解上下文管理机制: 每个线程或协程都有自己的内存空间保存自身对应的数据
2. 作用
- 为每一个线程或协程创建一个独立的内存空间,使得线程或协程对自己的内存中的数据进行操作,实现了(线程/协程)与(线程/协程)之间的数据隔离
Flask的请求上下文管理机制
1. Flask 请求上下文管理机制的说明
- 请求上下文包含了: request、session
- 注意: 请求上下文和app上下文所使用的 Local LocalStack LocalProxy 都是同一个类(即: 请求上下文 和 app上下文所生成的数据都会保存在同一个 __storage__ 字典内)
2. Flask 请求上下文管理机制重要源码分析
- 类和方法的说明:
- Local 类: 为每个线程或协程开辟各自的空间储存数据
- 通俗理解: Local 类创建了一个名为 __storage__ 字典存储着每个线程或协程的数据
- LocalStack 类: 帮助我们对 __storage__ 字典下的 stack 列表维护成一个栈(即: 后进先出)
- 通俗理解: 帮助我们对 __storage__ 字典下的 stack 列表进行添加和删除操作
- RequestContext 类: 存储着request请求信息和session等其他相关方法的类
- 通俗理解: 实例化一个 RequestContext 类得到一个 ctx 对象,且ctx对象下有request请求信息和session等其他相关方法,然后将该ctx对象保存在 __storage__ 字典下指定线程或协程下的 stack 列表里
- LocalProxy 类: 对 ctx 对象(即: request_context 对象)下的 request session 进行操作(即: 增删改查)
- 通俗理解: 调用在 _lookup_req_object 函数的基础上所创建的偏函数获取到 ctx 对象,然后对 ctx 对象(即: request_context 对象)下的 request session 进行操作(即: 增删改查)
- _lookup_req_object 函数: 调用 LocalStack 下的 top 方法获取 __storage__ 下的 ctx 对象(即:request_context对象)中指定的属性(如: request、session)
- 通俗理解: 通过 _lookup_req_object 函数可以获取到保存在 __storage__ 字典下指定线程或协程下的 stack 列表里 ctx 对象中的指定属性
- 所存储的数据结构
__storage__ = {
'线程或协程的唯一标识': {'stack': [ctx, xxx, xxx]},
'线程或协程的唯一标识': {'stack': [ctx, xxx, xxx]},
'线程或协程的唯一标识': {'stack': [ctx, xxx, xxx]},
……
}
- 查看重要源码
from flask import globals
- 重要的源代码
# f.py
import functools
# 如果有协程就使用协程,如果没有则使用线程
try:
from greenlet import getcurrent as get_ident
except ImportError:
try:
from thread import get_ident
except ImportError:
from _thread import get_ident
# 为每个线程或协程开辟各自的空间储存数据
class Local(object):
__slots__ = ("__storage__", "__ident_func__") # 设置对象允许访问的变量或方法
def __init__(self):
# 调用 object.__setattr__ 方法,先将 __storage__ 和 __ident_func__ 的属性值添加到 Local 类中,然后 __setattr__ 或 __delattr__ 就可以进行调用
object.__setattr__(self, "__storage__", {}) # __storage__ 用于存储各个线程或协程的数据的字典
"""
__storage__ 初始化的数据结构
__storage__ = {}
__storage__ 添加数据后的数据结构
__storage__ = {
'线程或协程的唯一标识': {key: value, ……},
'线程或协程的唯一标识': {key: value, ……},
'线程或协程的唯一标识': {key: value, ……},
……
}
"""
object.__setattr__(self, "__ident_func__", get_ident) # __ident_func__ -> 获取线程或协程的唯一标记的方法
# 获取 __storage__ 中的值
def __getattr__(self, name):
try:
return self.__storage__[self.__ident_func__()][name]
except KeyError:
raise AttributeError(name)
# 添加或修改 __storage__ 中的值
def __setattr__(self, name, value):
ident = self.__ident_func__() # 获取协程或线程的唯一标识
storage = self.__storage__ # 获取用于存储各个线程或协程的数据的字典
try:
storage[ident][name] = value
except KeyError:
storage[ident] = {name: value}
# 删除 __storage__ 中的值
def __delattr__(self, name):
try:
del self.__storage__[self.__ident_func__()][name]
except KeyError:
raise AttributeError(name)
# 帮助我们对 __storage__ 字典下的 stack 列表维护成一个栈(即: 后进先出) -> 通俗理解: 帮助我们对 __storage__ 字典下的 stack 列表进行添加和删除操作
class LocalStack(object):
def __init__(self):
self._local = Local() # 实例化local对象
"""
调用该类对 __storage__ 操作后的数据结构
__storage__ = {
'线程或协程的唯一标识': {'stack': [xxx, xxx, xxx]},
'线程或协程的唯一标识': {'stack': [xxx, xxx, xxx]},
'线程或协程的唯一标识': {'stack': [xxx, xxx, xxx]},
……
}
"""
# 往 __storage__ 中的 stack 列表添加值
def push(self, value):
rv = getattr(self._local, "stack", None) # 等同于 self._local.stack -> 执行 Local 类中的 __getattr__ 方法
if rv is None:
self._local.stack = rv = [] # 执行 Local 类中的 __setattr__ 方法
rv.append(value)
return rv
# 删除 __storage__ 中的 stack 列表的值,如果 stack 列表只有一个则不进行删除,当请求结束的时候就会调用该方法删除当前线程中的指定 ctx 对象
def pop(self):
stack = getattr(self._local, "stack", None) # 等同于 self._local.stack -> 执行 Local 类中的 __getattr__ 方法
if stack is None:
return None
elif len(stack) == 1:
# release_local(self._local)
return stack[-1]
else:
return stack.pop()
# 获取 __storage__ 中的 stack 列表的值
@property
def top(self):
try:
return self._local.stack[-1]
except (AttributeError, IndexError):
return None
# 代理 -> 对 ctx/app_ctx 对象(即: request_context/app_context 对象)下的 request session g app 进行操作(即: 增删改查)
class LocalProxy(object):
__slots__ = ("__local", "__dict__", "__name__", "__wrapped__")
def __init__(self, local, name=None):
"""
:param local: 偏函数
:param name: request、session、g、None
"""
"""
object.__setattr__(self, "_LocalProxy__local", local) 的解释:
1. 将 local 赋值给 _LocalProxy__local 属性,该属性可以通过 self.__local 进行访问
2. _LocalProxy__local属性名 等于 __local 属性名
3. 因为解释器会将 __local 替换为 _classname__local属性名 为确保名称不会与另一个类中的类似名称重叠的方式
"""
object.__setattr__(self, "_LocalProxy__local", local) # 将 local 赋值给 _LocalProxy__local 属性,该属性可以通过 self.__local 进行访问
object.__setattr__(self, "__name__", name) # 将 name 赋值给 __name__ 属性
if callable(local) and not hasattr(local, "__release_local__"):
object.__setattr__(self, "__wrapped__", local)
# 调用偏函数获取 ctx 对象(即: request_context 对象)
def _get_current_object(self):
if not hasattr(self.__local, "__release_local__"):
return self.__local() # 调用偏函数获取 ctx 对象(即: request_context 对象)
try:
return getattr(self.__local, self.__name__)
except AttributeError:
raise RuntimeError("no object bound to %s" % self.__name__)
# 当 LocalProxy 所实例化的对象执行了 对象.属性名 的时候就会执行该方法
def __getattr__(self, name):
if name == "__members__":
return dir(self._get_current_object())
return getattr(self._get_current_object(), name) # 调用偏函数获取 ctx 对象(即: request_context 对象),然后使用反射获取 ctx 对象下的对应 request、session、g
# 当 LocalProxy 所实例化的对象执行了 对象.属性名=xxx 的时候就会执行该方法
__setattr__ = lambda x, n, v: setattr(x._get_current_object(), n, v)
# 当 LocalProxy 所实例化的对象执行了 del 对象.属性名 的时候就会执行该方法
__delattr__ = lambda x, n: delattr(x._get_current_object(), n)
# 当 LocalProxy 所实例化的对象执行了 print/str(对象.属性名) 的时候就会执行该方法
__str__ = lambda x: str(x._get_current_object())
# request 类
class Request(object):
def __init__(self):
self.method = 'GET'
self.form = 123
# session 类
class Session(object):
def __init__(self):
self.name = 'Kevin'
self.age = 18
# 一个拥有request和session信息的类
class RequestContext(object):
def __init__(self):
self.request = Request()
self.session = Session()
_request_ctx_stack = LocalStack() # 实例化 LocalStack 得到 _request_ctx_stack 对象
request_context = RequestContext() # 实例化一个 request_context 对象,里面拥有 request 和 session 等属性
_request_ctx_stack.push(request_context) # 将 request_context 对象,添加到 __storage__ 中的 stack 列表中
# 调用 LocalStack 下的 top 方法获取 __storage__ 下的 request_context 对象,然后根据传入的属性名通过反射获取 request_context 对象下对应的属性值
def _lookup_req_object(name):
ctx = _request_ctx_stack.top # 调用 LocalStack 下的 top 方法获取 __storage__ 下的 ctx 对象(即:request_context 对象)
return getattr(ctx, name) # 等同于 ctx.request 或者 ctx.session
# 通过 LocalProxy 对 ctx 对象(即: request_context 对象)下的 request session 进行操作(即: 增删改查)
request = LocalProxy(functools.partial(_lookup_req_object, 'request'))
session = LocalProxy(functools.partial(_lookup_req_object, 'session'))
- 获取 request 或 session 的方式一
- 在视图函数中也可以通过 flask.globals._request_ctx_stack 中的 _request_ctx_stack 进行获取
# v.py
from f import _request_ctx_stack
request = _request_ctx_stack.top.request
print(request.method) # GET
session = _request_ctx_stack.top.session
print(session.name) # Kevin
- 获取 request 或 session 的方式二
# v.py
from f import request, session
print(request.method) # GET
print(session.name) # Kevin
3. Flask 请求上下文管理机制流程图
- 获取 request 或 session 的方式一

- 获取 request 或 session 的方式二

Flask的app上下文管理机制
1. Flask app上下文管理机制的说明
- 请求上下文包含了: app、g
- 注意: app上下文和请求上下文所使用的 Local LocalStack LocalProxy 都是同一个类(即: 请求上下文 和 app上下文所生成的数据都会保存在同一个 __storage__ 字典内)
2. Flask 请求上下文管理机制重要源码分析
- 类和方法的说明:
- Local 类: 为每个线程或协程开辟各自的空间储存数据
- 通俗理解: Local 类创建了一个名为 __storage__ 字典存储着每个线程或协程的数据
- LocalStack 类: 帮助我们对 __storage__ 字典下的 stack 列表维护成一个栈(即: 后进先出)
- 通俗理解: 帮助我们对 __storage__ 字典下的 stack 列表进行添加和删除操作
- AppContext 类: 存储着app和g等其他相关方法的类
- 通俗理解: 实例化一个 AppContext 类得到一个 app_ctx 对象,且app_ctx对象下有app和g等其他相关方法,然后将该app_ctx对象保存在 __storage__ 字典下指定线程或协程下的 stack 列表里
- LocalProxy 类: 对 app_ctx 对象(即: app_context 对象)下的 g app 进行操作(即: 增删改查)
- 通俗理解: 调用在 _lookup_app_object 函数的基础上所创建的偏函数获取到 app_ctx 对象,然后对 app_ctx 对象(即: app_context 对象)下的 g 进行操作(即: 增删改查)
- 通俗理解: 调用 _find_app 函数获取到 app_ctx 对象,然后对 app_ctx 对象(即: app_context 对象)下的 app 进行操作(即: 增删改查)
- _lookup_app_object 函数: 调用 LocalStack 下的 top 方法获取 __storage__ 下的 app_ctx 对象(即:app_context对象)中指定的属性(如: g 等)
- 通俗理解: 通过 _lookup_app_object 函数可以获取到保存在 __storage__ 字典下指定线程或协程下的 stack 列表里 app_ctx 对象中的指定属性
- _find_app 函数: 调用 LocalStack 下的 top 方法获取 __storage__ 下的 app_ctx 对象(即:app_context对象)中指定的属性 app
- 通俗理解: 通过 _find_app 函数可以获取到保存在 __storage__ 字典下指定线程或协程下的 stack 列表里 app_ctx 对象中的指定属性 app
- 所存储的数据结构
__storage__ = {
'线程或协程的唯一标识': {'stack': [app_ctx, xxx, xxx]},
'线程或协程的唯一标识': {'stack': [app_ctx, xxx, xxx]},
'线程或协程的唯一标识': {'stack': [app_ctx, xxx, xxx]},
……
}
- 查看重要源码
from flask import globals
- 重要的源代码
# f.py
import functools
# 如果有协程就使用协程,如果没有则使用线程
try:
from greenlet import getcurrent as get_ident
except ImportError:
try:
from thread import get_ident
except ImportError:
from _thread import get_ident
# 为每个线程或协程开辟各自的空间储存数据
class Local(object):
__slots__ = ("__storage__", "__ident_func__") # 设置对象允许访问的变量或方法
def __init__(self):
# 调用 object.__setattr__ 方法,先将 __storage__ 和 __ident_func__ 的属性值添加到 Local 类中,然后 __setattr__ 或 __delattr__ 就可以进行调用
object.__setattr__(self, "__storage__", {}) # __storage__ 用于存储各个线程或协程的数据的字典
"""
__storage__ 初始化的数据结构
__storage__ = {}
__storage__ 添加数据后的数据结构
__storage__ = {
'线程或协程的唯一标识': {key: value, ……},
'线程或协程的唯一标识': {key: value, ……},
'线程或协程的唯一标识': {key: value, ……},
……
}
"""
object.__setattr__(self, "__ident_func__", get_ident) # __ident_func__ -> 获取线程或协程的唯一标记的方法
# 获取 __storage__ 中的值
def __getattr__(self, name):
try:
return self.__storage__[self.__ident_func__()][name]
except KeyError:
raise AttributeError(name)
# 添加或修改 __storage__ 中的值
def __setattr__(self, name, value):
ident = self.__ident_func__() # 获取协程或线程的唯一标识
storage = self.__storage__ # 获取用于存储各个线程或协程的数据的字典
try:
storage[ident][name] = value
except KeyError:
storage[ident] = {name: value}
# 删除 __storage__ 中的值
def __delattr__(self, name):
try:
del self.__storage__[self.__ident_func__()][name]
except KeyError:
raise AttributeError(name)
# 帮助我们对 __storage__ 字典下的 stack 列表维护成一个栈(即: 后进先出) -> 通俗理解: 帮助我们对 __storage__ 字典下的 stack 列表进行添加和删除操作
class LocalStack(object):
def __init__(self):
self._local = Local() # 实例化local对象
"""
调用该类对 __storage__ 操作后的数据结构
__storage__ = {
'线程或协程的唯一标识': {'stack': [xxx, xxx, xxx]},
'线程或协程的唯一标识': {'stack': [xxx, xxx, xxx]},
'线程或协程的唯一标识': {'stack': [xxx, xxx, xxx]},
……
}
"""
# 往 __storage__ 中的 stack 列表添加值
def push(self, value):
rv = getattr(self._local, "stack", None) # 等同于 self._local.stack -> 执行 Local 类中的 __getattr__ 方法
if rv is None:
self._local.stack = rv = [] # 执行 Local 类中的 __setattr__ 方法
rv.append(value)
return rv
# 删除 __storage__ 中的 stack 列表的值,如果 stack 列表只有一个则不进行删除,当请求结束的时候就会调用该方法删除当前线程中的指定 app_ctx 对象
def pop(self):
stack = getattr(self._local, "stack", None) # 等同于 self._local.stack -> 执行 Local 类中的 __getattr__ 方法
if stack is None:
return None
elif len(stack) == 1:
# release_local(self._local)
return stack[-1]
else:
return stack.pop()
# 获取 __storage__ 中的 stack 列表的值
@property
def top(self):
try:
return self._local.stack[-1]
except (AttributeError, IndexError):
return None
# 代理 -> 对 ctx/app_ctx 对象(即: request_context/app_context 对象)下的 request session g app 进行操作(即: 增删改查)
class LocalProxy(object):
__slots__ = ("__local", "__dict__", "__name__", "__wrapped__")
def __init__(self, local, name=None):
"""
:param local: 偏函数
:param name: request、session、g、None
"""
"""
object.__setattr__(self, "_LocalProxy__local", local) 的解释:
1. 将 local 赋值给 _LocalProxy__local 属性,该属性可以通过 self.__local 进行访问
2. _LocalProxy__local属性名 等于 __local 属性名
3. 因为解释器会将 __local 替换为 _classname__local属性名 为确保名称不会与另一个类中的类似名称重叠的方式
"""
object.__setattr__(self, "_LocalProxy__local", local) # 将 local 赋值给 _LocalProxy__local 属性,该属性可以通过 self.__local 进行访问
object.__setattr__(self, "__name__", name) # 将 name 赋值给 __name__ 属性
if callable(local) and not hasattr(local, "__release_local__"):
object.__setattr__(self, "__wrapped__", local)
# 调用偏函数获取 ctx/app_ctx 对象(即: request_context/app_context 对象)
def _get_current_object(self):
if not hasattr(self.__local, "__release_local__"):
return self.__local() # 调用偏函数获取 ctx/app_ctx 对象(即: request_context/app_context 对象)
try:
return getattr(self.__local, self.__name__)
except AttributeError:
raise RuntimeError("no object bound to %s" % self.__name__)
# 当 LocalProxy 所实例化的对象执行了 对象.属性名 的时候就会执行该方法
def __getattr__(self, name):
if name == "__members__":
return dir(self._get_current_object())
return getattr(self._get_current_object(), name) # 调用偏函数获取 ctx/app_ctx 对象(即: request_context/app_context 对象),然后使用反射获取 ctx/app_ctx 对象下的对应 request、session、g
# 当 LocalProxy 所实例化的对象执行了 对象.属性名=xxx 的时候就会执行该方法
__setattr__ = lambda x, n, v: setattr(x._get_current_object(), n, v)
# 当 LocalProxy 所实例化的对象执行了 del 对象.属性名 的时候就会执行该方法
__delattr__ = lambda x, n: delattr(x._get_current_object(), n)
# 当 LocalProxy 所实例化的对象执行了 print/str(对象.属性名) 的时候就会执行该方法
__str__ = lambda x: str(x._get_current_object())
# 这里的app所指的是通过 Flask 所实例化出来的 app
class App:
def __init__(self):
self.config = 'app的配置'
class G:
def __init__(self):
self.name = 'Kevin'
# 一个拥有app和g信息的类
class AppContext(object):
def __init__(self):
self.app = App() # 注意: 这里的app所指的是通过 Flask 所实例化出来的 app 对象
self.g = G()
_app_ctx_stack = LocalStack() # 实例化 LocalStack 得到 _app_ctx_stack 对象
app_context = AppContext() # 实例化一个 app_context 对象,里面拥有 app 和 g 等属性
_app_ctx_stack.push(app_context) # 将 app_context 对象,添加到 __storage__ 中的 stack 列表中
# 调用 LocalStack 下的 top 方法获取 __storage__ 下的 app_context 对象,然后根据传入的属性名通过反射获取 app_context 对象下对应的属性值
def _lookup_app_object(name):
app_ctx = _app_ctx_stack.top # 调用 LocalStack 下的 top 方法获取 __storage__ 下的 app_ctx 对象(即:app_context 对象)
return getattr(app_ctx, name) # 等同于 app_ctx.g
# 调用 LocalStack 下的 top 方法获取 __storage__ 下的 app_context 对象下的 app 对象
def _find_app():
app_ctx = _app_ctx_stack.top # 调用 LocalStack 下的 top 方法获取 __storage__ 下的 app_ctx 对象(即:app_context 对象)
return app_ctx.app
# 通过 LocalProxy 对 app_ctx 对象(即: app_context 对象)下的 app g 进行操作(即: 增删改查)
current_app = LocalProxy(_find_app)
g = LocalProxy(functools.partial(_lookup_app_object, 'g'))
- 获取 current_app 或 g 的方式一
- 在视图函数中也可以通过 flask.globals._app_ctx_stack 中的 _app_ctx_stack 进行获取
# v.py
from f import _app_ctx_stack
current_app = _app_ctx_stack.top.app
print(current_app.config) # app的配置
g = _app_ctx_stack.top.g
print(g.name) # Kevin
- 获取 current_app 或 g 的方式二
# v.py
from f import current_app, g
print(current_app.config) # app的配置
print(g.name) # Kevin
3. Flask app上下文管理机制流程图
- 获取 current_app 或 g 的方式一

- 获取 current_app 或 g 的方式二

上下文管理机制总的流程图
- 所存储的数据结构
__storage__ = {
'线程或协程的唯一标识': {'stack': [ctx, app_ctx, xxx]},
'线程或协程的唯一标识': {'stack': [ctx, app_ctx, xxx]},
'线程或协程的唯一标识': {'stack': [ctx, app_ctx, xxx]},
……
}
- 请求和app上下文管理机制总的流程图

← werkzeug 模块的使用 中间件 →