zl程序教程

您现在的位置是:首页 >  后端

当前栏目

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

线程 请求 本地 Flask 上下文 补充
2023-09-14 08:57:25 时间

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__()之后。
应用上下文并不是应用启动之后生成的唯一上下文

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