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__()之后。
应用上下文并不是应用启动之后生成的唯一上下文
······有空写吧,该吃饭了。。
本文来自博客园,作者:一石数字欠我15w!!!,转载请注明原文链接:https://www.cnblogs.com/52-qq/p/9340804.html