flask 请求上下文
一篇引用大牛的
https://www.cnblogs.com/zhaopanpan/p/9457343.html
### 线程安全 ```python
# 线程不安全
class Foo(object):
pass foo = Foo()
foo.num = 1 import time
import threading def my_num(i):
foo.num = i
time.sleep(1)
print(foo.num,threading.current_thread().ident) for i in range(20):
th = threading.Thread(target=my_num,args=(i,))
th.start()
---------------------------------------------------------------------------- # 线程安全
from threading import local
class Foo(local):
pass foo = Foo()
foo.num = 1 import time
import threading def my_num(i):
foo.num = i
time.sleep(1)
print(foo.num,threading.current_thread().ident) for i in range(200000):
th = threading.Thread(target=my_num,args=(i,))
th.start() # 开辟新空间 - 浪费了部分资源 - 速度保证 - 保证安全
"""
{
16232:[request],# 123
17164:[request],# 456
9088: [request],# 567
16084:[request],# 789
} Threading.local
Flask 上下文机制就是使用的 Threading.local
线程进来 开辟一个空间给这个线程,线程操作的所有任务,都会复制一份儿到空间中
"""
``` ### 栈 Stack ```python
# Stack
class MyStack(object):
data = [] def __setattr__(self, key, value):
self.push(key,value) def push(self,key,value):
self.data.append({key:value}) def top(self):
return self.data.pop() my_stack = MyStack() my_stack.name = 666 # [{name:666}]
my_stack.name = 777 # [{name:666},{name:777}] print(my_stack.data) # my_stack.push(666)
# my_stack.push(777)
# my_stack.push(888)
#
# print(my_stack.top(),my_stack.data)
# print(my_stack.top(),my_stack.data)
# print(my_stack.top(),my_stack.data)
``` ### 局部的栈 LocalStack ```python
# LocalStack 安全的 栈
from threading import get_ident # 获取当前线程的 id
import threading class MyLocalStack(object):
storage={}
def push(self,item):
try:
self.storage[get_ident()].append(item)
except:
self.storage[get_ident()]=[item] def top(self):
return self.storage[get_ident()].pop() my_local_stack = MyLocalStack() import time
def go(i):
my_local_stack.push(i)
time.sleep(1)
# my_local_stack.top() for i in range(5):
th = threading.Thread(target=go,args=(i,))
th.start() print(my_local_stack.storage)
``` ## flask 的 请求上下文 + ## werkzeug + flask 的 wsgi ```python
from werkzeug.wrappers import Request,Response
from werkzeug.serving import run_simple @Request.application
def app(environ):
print(environ)
return Response("200OK") run_simple("0.0.0.0",9527,app) ``` ```python
from flask import Flask
app = Flask(__name__) if __name__ == '__main__':
app.run(host='0.0.0.0',port=7088)
app.__call__
app.wsgi_app ``` ### 上文 1. 从 **`run()`** 开始 + 进入源码 其中的 >> `self = app = Flask()` + 导入了 `from werkzeug.serving import run_simple` 执行了 `run_simple(host, port, self, **options)` 方法 + 看这一句 `run_simple("0.0.0.0",9527, app) ` 也就是说 self 会执行 >> `self = app = Flask() = self()` + 也就 == app() 对象() 执行 类的 `__call__()` 方法 2. `__call__() ` 执行了 `self.wsgi_app(environ, start_redponse)` **environ = request 原始信息** 3. 进入 `app.wsgi_app` + `def wsgi_app(self, environ, start_response):` >> self = app = Flask() + self 执行了这个方法 `ctx = self.request_context(environ)` 方法中执行了 一个类 `RequestContext(self, environ)` ctx.py文件中 >> 这个对象中 包含了 两个 值 requset/session ctx = requsetcontext --> requset/session + 在这个类中 的 初始化方法 中 `def __init__(self, app, environ, request=None):` >> self = RequestContext ->request/session app = Flask request=None 执行方法 `request = app.request_class(environ)` 这个方法将 environ 序列化 出了 request对象 就是可以使用 request.method requset.form ... 方法 了 + 执行ctx.push() 方法 4. ctx.push() 方法 + 方法中执行了 `top = _request_ctx_stack.top` --> `_request_ctx_stack = LocalStack()` 实例化时的 `__init__` 方法中 初始化了 两个 对象 >> `self._local = {"__storage__": {}, "__ident_func__": get_ident}` >`get_ident` 获取线程 或携程的 id 并没有执行 + `_request_ctx_stack = {"__storage__": {}, "__ident_func__": get_ident}` + `.top ` 方法 执行了 `self._local.stact[-1]` .stack 调用 Local(object): 对象的 `__getattr__(self) 方法` + 方法中 调用 `self.__storage__[self.__ident_func__()][name]` 也就是从 `{"__storage__": {}, "__ident_func__": get_ident}` 中的 `__storage__` 中通过key 取值 此时 `__storage__` 中为 空字典 报错 抛出异常 `AttributeError(name)` 这个异常在上面的 top 方法中 被捕获 返回 一个 None 返回 **top = None** 之后的 if 判断不成立 + 之后又执行了 `_request_ctx_stack.push(self)` 代码 其中的 ` _request_ctx_stack = {"__storage__": {}, "__ident_func__": get_ident}` + 执行了.push(self) 方法 这个self = ctx = requset/session 进入 push() 方法 + `def push(self, obj)`这里面的 self 是 ` _request_ctx_stack = {"__storage__": {}, "__ident_func__": get_ident}` obj = ctx = requset/session 执行 : ` rv = getattr(self._local, 'stack', None)` `self._local = {"__storage__": {}, "__ident_func__": get_ident}` rv = None -> if判断 执行` self._local.stack = rv = [] rv.append(obj) ` 走对象的 `__setattr__(self,name,value)`方法 返回 =>> `{"__storage__": {7088:{"stack": rv=[] }}, "__ident_func__": get_ident}` + 返回 rv.append(obj) ==>`{"__storage__": {7088:{"stack": [ctx=>request/session] }}, "__ident_func__": get_ident}` `rv=[ctx=>request/session] ` 并没有接收返回值 执行完之后 `self._local = {"__storage__": {7088:{"stack": [ctx=>request/session] }}, "__ident_func__": get_ident}` ### 下文 + 使用时才执行 ```python
@app.route("/")
def login():
if requset.method =='POST':
...
# requset.method 之后启动下文
``` + 进入 request ```python
# partial 偏函数
request = LocalProxy(
partial(
_lookup_req_object,
'request'
)
)
``` + `_lookup_req_object` ```python
def _lookup_req_object(name):
top = _request_ctx_stack.top
# _request_ctx_stack = self._local = {"__storage__": {7088:{"stack": [ctx=>request/session] }}, "__ident_func__": get_ident} 调用.top 方法
if top is None:
raise RuntimeError(_request_ctx_err_msg)
return getattr(top, name)
``` + .top 中 执行了 `self._local.stack[-1]` ```python
# 执行 self._local的 __getattr__ 方法
def __getattr__(self, name):
try:
return self.__storage__[self.__ident_func__()][name]
except KeyError:
raise AttributeError(name) # 返回了 [ctx => request / session ]
``` 执行 [-1] 得到 `ctx => request / session` + `top = ctx => request / session` + `getattr(top, name)` name = request 从偏函数传递过来的 方法 得到了 一个 request 对象 及 request 的真身 + 查看` LocalProxy(偏函数没被执行的 )` 实例化 执行`def __init__(self, local, name=None):` local = request 的偏函数 ```python
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)
``` + request.method 执行 .方法 调用 `__getattr__()` 执行 `getattr(self._get_current_object(), name)` ```python
def _get_current_object(self):
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__)
``` `__local = local = requset偏函数执行 = requset` + `getattr(request, name)` name = method + ### 查看 LocalProxy 类 包含了 所有面向对象的 特殊方法 ### 应用上下文 + 会在 离线脚本 的时候使用 + 从 `app.wsgi_app` 中 找到 `ctx.push()` 的方法 + `app_ctx = _app_ctx_stack.top` 这个 就是应用上下文 ```python
app_ctx = _app_ctx_stack.top
if app_ctx is None or app_ctx.app != self.app:
app_ctx = self.app.app_context()
app_ctx.push()
self._implicit_app_ctx_stack.append(app_ctx)
else:
self._implicit_app_ctx_stack.append(None)
``` 1. `_app_ctx_stack = {"__storage__": {}, "__ident_func__": get_ident}`
2. `.top` 方法 返回的还是 None
3. `app_ctx = None` + `app_ctx = self.app.app_context()` 序列化 app 得到 AppContext(app,g) -> requestcontext(request/session) + `app_ctx.push()` 得到 `self._local = {"__storage__": {7088:{"stack": [app_ctx(app, g)] }}, "__ident_func__": get_ident}` g会在 离线脚本 的时候使用 `current_app = LocalProxy(_find_app)` = app = Flask() ```python
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 独立的 app
``` 请求结束之后执行 pop 方法 删除缓存 `g = LocalProxy(partial(_lookup_app_object, 'g'))`
flask 请求上下文的更多相关文章
- Flask(4)- flask请求上下文源码解读、http聊天室单聊/群聊(基于gevent-websocket)
一.flask请求上下文源码解读 通过上篇源码分析,我们知道了有请求发来的时候就执行了app(Flask的实例化对象)的__call__方法,而__call__方法返回了app的wsgi_app(en ...
- flask 请求上下文源码(转)
本篇阅读目录 一.flask请求上下文源码解读 二.http聊天室(单聊/群聊)- 基于gevent-websocket 回到顶部 转:https://www.cnblogs.com/li-li/p/ ...
- flask请求上下文
先看一个例子: #!/usr/bin/env python # -*- coding:utf-8 -*- import threading # local_values = threading.loc ...
- Flask请求上下文源码讲解,简单的群聊单聊web
请求上下文流程图 群聊html代码 <!DOCTYPE html> <html lang="en"> <head> <meta chars ...
- flask请求上下文 (转)
本篇阅读目录 一.flask中的CBV 二.werkzeug + 上下文初步解读 三.偏函数和线程安全 回到顶部 一.flask中的CBV 对比django中的CBV,我们来看一下flask中的CBV ...
- flask请求上下文源码分析
一.什么是上下文 每一段程序都有很多外部变量,只有像add这种简单的函数才是没有外部变量的,一旦你的一段程序有了外部变量,这段程序就不完整了,不能独立运行,你为了使他们能运行,就要给所有的外部变量一个 ...
- Flask请求上下文request
- python 全栈开发,Day139(websocket原理,flask之请求上下文)
昨日内容回顾 flask和django对比 flask和django本质是一样的,都是web框架. 但是django自带了一些组件,flask虽然自带的组件比较少,但是它有很多的第三方插件. 那么在什 ...
- flask的请求上下文源码解读
一.flask请求上下文源码解读 通过上篇源码分析( ---Flask中的CBV和上下文管理--- ),我们知道了有请求发来的时候就执行了app(Flask的实例化对象)的__call__方法,而__ ...
随机推荐
- InnoDB log file 设置多大合适?
简介: 数据库的东西,往往一个参数就牵涉N多知识点.所以简单的说一下.大家都知道innodb是支持事务的存储引擎.事务的四个特性ACID即原子性(atomicity),一致性(consistency) ...
- thinkphp无法安装提示修改mysql配置
在安装以thinkphp为框架的系统时数据库连接错误,提示修改sql-mode或sql_mode为NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION.那我们就顺着提示 ...
- 20190223 Hadoop生态圈,关于大数据
周六参加了一场,大数据基础培训,讲得比较详细.培训的讲师对于互联网行业职位萎缩也有相对的解释,也还介绍了新的职位的诞生. 以前对于大数据的理解,就是超大的数据量,但对大数据开发不甚了解. 大数据平台的 ...
- Python3学习之路~0 目录
目录 Python3学习之路~2.1 列表.元组操作 Python3学习之路~2.2 简单的购物车程序 Python3学习之路~2.3 字符串操作 Python3学习之路~2.4 字典操作 Pytho ...
- 【leetcode】部分思路整理
题目: 求一个树的最小深度. 思路: 思路一:递归 若为空树返回0: 若左子树为空,则返回右子树的最小深度+1:(加1是因为要加上根这一层,下同) 若右子树为空,则返回左子树的 ...
- secure CRT常用的查看服务器日志命令
tail -f /(日志文件目录) 查看日志命令ctrl+c停止打印ls -al 查看文件的详细信息路径等vi /(日志文件目录) 打开日志/搜索字符退出:按ESC后,按“:”,输入q, ...
- 【Java】-NO.16.EBook.4.Java.1.002-【疯狂Java讲义第3版 李刚】- 数据类型
1.0.0 Summary Tittle:[Java]-NO.16.EBook.4.Java.1.002-[疯狂Java讲义第3版 李刚]- 数据类型 Style:EBook Series:Java ...
- Windows 下MySql Replication(复制)配置
环境准备 到官网下载mysql-installer-web-community-5.7.21.0.msi并安装,选择MySql Workbench,记录安装时root输入的密码. 需要安装在两台机器上 ...
- TortoiseGit推送代码到Gerrit的过程
gerrit的安装不在本博客的说明范围中,本博客阐述的是使用TortoiseGit 提交代码到gerrit上的步骤和配置. 一.Git 说明:这个工具只要用来做一个仿真的linux环境,可以执行大部分 ...
- Centos6.5建立本地YUM源
很多情况下公司的服务器是不允许连外网的,那么安装软件的时候就很不方便了,这里就需要建立一个本地YUM源了. 文件位置:/etc/yum.repos.d/ 后缀一定是.repo结束. 下面我们搭建 ...