一篇引用大牛的
https://www.cnblogs.com/zhaopanpan/p/9457343.html

### 线程安全  

```python# 线程不安全class Foo(object):    pass

foo = Foo()foo.num = 1

import timeimport 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 localclass Foo(local):    pass

foo = Foo()foo.num = 1

import timeimport 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.localFlask 上下文机制就是使用的 Threading.local线程进来 开辟一个空间给这个线程,线程操作的所有任务,都会复制一份儿到空间中"""```

### 栈  Stack

```python# Stackclass 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  # 获取当前线程的 idimport 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 timedef 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 

```pythonfrom werkzeug.wrappers import Request,Responsefrom werkzeug.serving import run_simple

@Request.applicationdef app(environ):    print(environ)    return Response("200OK")

run_simple("0.0.0.0",9527,app)  

```

```pythonfrom flask import Flaskapp = 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()

```pythondef _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'))`

转载于:https://www.cnblogs.com/zhangchen-sx/p/10588088.html

flask 请求上下文相关推荐

  1. python Flask 10 Flask请求上下文管理werkzeug

    什么是上下文    上下文相当于一个容器,保存了 Flask 程序运行过程中的一些信息. Flask 中有两种上下文,请求上下文(request 和 session )和应用上下文(current_a ...

  2. flask 核心 之 应用上下文 及 请求上下文

    Werkzeugs 是 Flask 的底层WSGI库. 什么是WSGI? 一段简单的app: def dispath_request(self, request):return Response('H ...

  3. Web框架——Flask系列之请求上下文与应用上下文请求钩子Flask-Script扩展命令行(十七)

    一.请求上下文和应用上下文 请求上下文(request context) request和session都属于请求上下文对象. 应用上下文(application context) current_a ...

  4. flask中的请求上下文

    2019独角兽企业重金招聘Python工程师标准>>> 根据前一篇应用上下文可知,请求上下文的作用域是发生在请求到来之后. 如有一个应用函数返回用户应该跳转到的URL.想象它总是会跳 ...

  5. Flask的上下文管理机制

    前引 在了解flask上下文管理机制之前,先来一波必知必会的知识点. 面向对象双下方法 首先,先来聊一聊面向对象中的一些特殊的双下划线方法,比如__call__.__getattr__系列.__get ...

  6. flask的上下文的机理与应用(转载+整理)

    请求上下文面向开发者使用的对象主要是request和session: 应用上下文面向开发者使用的对象主要是current_app和g; #------------------------------- ...

  7. Flask框架——上下文、flask_script扩展

    目录 上下文(引用池,引用区) flask_script扩展 上下文(引用池,引用区) 上下文:相当于一个容器,保存了 Flask 程序运行过程中的一些信息. 为了避免大量可有可无的参数把视图函数弄得 ...

  8. fragment怎么获得上下文环境_Flask 源码剖析 (三):Flask 的上下文机制 (上)

    写文章其实很费力,你的「在看」很重要. 前言 在面试 Python web 方面的工作时,如果你说自己阅读过 Flask 源码,那么 Flask 上下文机制的实现原理肯定会被问到,本篇文章就来剖析一下 ...

  9. Flask 应用上下文

    上下文管理 threading.local 请求上下文:RequstContext request session 应用上下文:AppContext app(current_app) g 1.请求到来 ...

  10. 应用上下文请求上下文

    用过 Flask 做 Web 开发的同学应该不会不记得 App Context 和 Request Context 这两个名字--这两个 Context 算是 Flask 中比较特色的设计.[1] 从 ...

最新文章

  1. JavaScript学习笔记—— 4. 变量、作用域和内存问题
  2. 如何让网站被百度谷歌快速收录
  3. 安装两个硬盘时应如何跳线?
  4. 工作总结3:axios里面的主要参数
  5. svg入门经典pdf_机器学习最好的入门课程是什么?
  6. Spring MVC中的基本流程
  7. java工程开发之图形化界面之(第六课)
  8. Early Z Culling 优化
  9. strace监视系统调用
  10. nginx启动只有master没有worker_深入探索Nginx工作原理
  11. Macro版Property Generator辅助工具
  12. Java 的运行机制
  13. Momentum, RMSprob and Adam
  14. 微信小程序动画效果集合
  15. 解决网页文字不能复制,复制网页文字的方法
  16. html在浏览器中的渲染原理,浏览器渲染原理
  17. 字节跳动、阿里等大厂的真实工作体验如何?看看四位程序员的自述
  18. 谷歌外链建设2022年如何判断和购买google优质外链
  19. 晒晒老衲用的WordPress插件
  20. L1-057 PTA使我精神焕发 (5 分) 天梯赛 详解

热门文章

  1. [UWP]了解模板化控件(8):ItemsControl
  2. Cloud Container Service experimentation
  3. linux 查看分区
  4. 让ProgressPar动起来
  5. “NLP的那些事儿”开张了!
  6. linux安装好的mysql rpm -qa |grep mysql不见
  7. Spring时间(Date)类型转换+自定义
  8. BUG Error:Execution failed for task ':app:dexDebug'.
  9. Java 中判断char 是否为空格 和空
  10. 模式窗口(Window.ShowModalDialogs)中提交不弹出新窗口