flask-本地线程-请求上下文补充

context(上下文)是flask里面非常好的设计,使用flask需要非常理解应用上下文和请求上下文这两个概念

本地线程

本地线程(thread local)希望不同的线程对于内容的修改只在线程内部发挥作用,线程内部互相不影响

from django.test import TestCase
import threading

mydata = threading.local()
mydata.number = 42

print(mydata.number)

logs = []

def f():
    mydata.number = 11
    logs.append(mydata.number)

thread = threading.Thread(target=f)
thread.start()
thread.join()
print(mydata.number)

可以看到,在线程的内部修改了mydata.number的值,但是没有影响到开始设置的值

本地线程的实现原理就是:在threading.current_thread().__dict__里添加一个包含对象mydata的id值的key,来保存不同的线程状态

werkzeug的Local

werkzeug自己实现了自己的本地线程。werkzeug.local.Local和threading.local的区别如下:

werkzeug使用了自定义的__storage__来保存不同线程下的状态

werkzeug提供了释放本地线程的release_local方法

werkzeug使用了两种方法来通过get_ident函数获取线程的标识符*(greenlet,系统线程,默认使用系统的,如果安装了greenlet则使用她)

werkzeug还实现了两种数据结构。

localstack:基于werkzeug.local.Local实现的栈结构,可以将对象推入,弹出,也可以快速拿到栈顶对象

localproxy:作用和名字一样,是标准的代理模式。构造次结构时接收一个可以调用的参数(一般是函数),这个函数执行后就是通过localstack实例化的栈的栈顶对象。

     基于localproxy对象的操作实力上都会转发到这个栈顶对象(也就是一个threadlocal上边)

Flask.request

from flask import Flask, request

app = Flask(__name__)

@app.route(‘/‘)
def xxx():
    name = request.args.get("name")

在这里,我们先引用了flask.request,但是直到用户访问xxx函数的使用才通过request.args.get获取请求的参数值,试想,引用的时候还没发生这个请求,那么请求上下文是怎么获得的呢?

flask.request就是一个获取名为_request_ctx_stack的栈顶对象的LocalProxy实例:

from functools import partial
from werkzeug.local import LocalProxy

def _lookup_req_object(name):
    top = _request_ctx_stack.top
    if top is None:
        raise RuntimeError("xxxxx")
    return getattr(top, name)

上面的逻辑可以正常使用,先来看看流程:

1:用户访问产生请求
2:在发生请求的过程中向_reqeust_ctx_stack推入这个请求的上下文对象,他会变成栈顶,request就会成为这个请求上下文,也就包含了这次请求的相关信息和数据
3:在视图函数中使用request就可以使用request.args.get(‘name‘)了
设想不使用LocalStack和LocalProxy的话,要想让视图函数访问的请求对象,就只能将其作为参数,一步步的传入视图函数中。这样做的缺点是会让每个视图函数都增加一个request参数,而flask却巧妙的使用了上下文把某些对象设置成全局访问,每个线程看到的上下文对象却是不同的,这样就巧妙的解决了这个问题

使用上下文

应用上下文的典型场景是缓存一些在发生请求之前要使用到的资源,比如生成数据库链接和缓存一些对象;请求上下文发生在HTTP请求的开始,WSGI server调用Flask.__call__()之后。应用上下文并不是应用启动之后生成的唯一上下文

······有空写吧,该吃饭了。。

原文地址:https://www.cnblogs.com/52-qq/p/9340804.html

时间: 2024-07-31 02:42:51

flask-本地线程-请求上下文补充的相关文章

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基础之AppContext应用上下文和RequestContext请求上下文(六)

前言 应用上下文和请求上下文存在的目的,官方文档讲的很清楚,可参考: http://www.pythondoc.com/flask/appcontext.html 应用上下文对象在没有请求的时候是可以单独存在的,但是请求上下文对象只有在收到请求后才会被创建.请求处理和应用上下文和请求上下文的关系是: 接收请求-->创建请求上下文-->请求上下文入栈-->创建该请求的应用上下文-->应用上下文入栈-->处理逻辑-->请求上下文出栈-->应用上下文出栈 系列文章 fl

flask 请求上下文源码(转)

本篇阅读目录 一.flask请求上下文源码解读 二.http聊天室(单聊/群聊)- 基于gevent-websocket 回到顶部 转:https://www.cnblogs.com/li-li/p/10252058.html#main 一.flask请求上下文源码解读 通过上篇源码分析,我们知道了有请求发来的时候就执行了app(Flask的实例化对象)的__call__方法,而__call__方法返回了app的wsgi_app(environ, start_response)方法的执行结果,而

Flask的请求上下文机制

准备知识 面向对象双下方法 __call__ 对象后面加括号,触发执行 为什么设计上下文这样的机制? 就是保证多线程环境下,实现线程之间的隔离. 在了解flask上下文机制之前,我们先了解下线程的数据安全. 线程安全 如上代码段,在1s内开启20个线程,执行add_num(),结果foo.num都为 19,说明线程间数据是不隔离的. 那么,如何保证线程间数据隔离呢? 有一种 threading.local 方法 Thread Local threading.local 在多线程操作时,为每一个线

2.5.1、程序和请求上下文

Flask 从客户端收到请求时,要让视图函数能访问一些对象,这样才能处理请求.请求对象就是一个很好的例子,它封装了客户端发送的 HTTP 请求. 要想让视图函数能够访问请求对象,一个显而易见的方式是将其作为参数传入视图函数,不过这会导致程序中的每个视图函数都增加一个参数. 除了访问请求对象,如果视图函数在处理请求时还要访问其他对象,情况会变得更糟. 为了避免大量可有可无的参数把视图函数弄得一团糟,Flask 使用上下文临时把某些对象变为全局可访问.有了上下文,就可以写出下面的视图函数: from

Python 本地线程

1. 本地线程,保证即使是多个线程,自己的值也是互相隔离. 2.普通对象演示 import threading import time class A(): pass a=A() def func(num): a.name=num time.sleep(1) print(a.name,threading.current_thread().name) 结果 D:\virtualenv\envs\vuedjango\Scripts\python.exe D:/test/flaskTest/flask

应用上下文和请求上下文

from flask import Flask,request,session,url_for,current_app from werkzeug.local import Local,LocalStack #线程隔离技术 #只要绑定在Local对象上的属性 #在每个线程中都是隔离 app = Flask(__name__) # print(current_app.name)#RuntimeError: Working outside of application context. #怎么解决上

IOC容器特性注入第七篇:请求上下文作用域

Ninject的对象作用域: Transient .InTransientScope() 每次调用创建新实例. Singleton .InSingletonScope() 单例,仅创建一个实例. Thread .InThreadScope() 每一个线程创建一个实例. Request .InRequestScope() 每当Web请求发起时创建一个实例,结束请求时释放实例 由于我们使用的web开发,所以一般都是InReuqestScope()的作用域,Kooboo对Ninject的作用域没有用,

让Flask处理异步请求

今天意外在网上看到一篇文章,写到 后端使用gunicorn+flask的方式,刚开始就直接使用flask跑,但是有一次就出现502了,发现由于flask是单进程处理请求的,不像Tornado的异步,同时访问的人数稍微过多,就会出现阻塞的情况,导致nginx出现502的问题 于是开始寻找flask处理异步请求的解决方案 首先 我不了解tornado的异步处理方式,有时间我会去了解一下 其次,我在实验里犯了一个错误,我随手用sleep(100)去做阻塞,造成的结果是整个进程被我挂起了,其实我只需要在