本篇内容介绍了“Flask的上下文管理详解”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
Flask线程间上下文安全
Falsk完成线程安全的原理,是在启动之后进程里维护request栈和app栈,栈是通过线程ID来保证每个请求的线程安全。
实现主要依赖三个类Local,LocalStack和LocalProxy,下面看一下具体的实现原理
三个类构建本地数据
Local
先看Local的源码,实质并不是Flask中定义的,而是Flask依赖的werkzeug库所定义。
可以看到其定义的两个属性__storage__, __ident_func__以及三个方法__getattr__,__setattr__,__release_local__。
属性__storage__是多层级字典,第一层key是隐含的线程ID或者协程ID,第二层的key是实际使用的关键字
属性__ident_func__可以看到是get_ident函数,get_ident函数要么是通过thread库获取当前执行单元的线程ID,要么是通过greenlet库获取当前执行协程的协程ID。
另外可以看到Local这个类的三个方法,实质是通过重写Python内置函数__setattr__和__getattr__来实现线程或者协程间数据隔离
获取local某属性时如:local.age实质触发的是__getattr__方法先获取到当前线程ID——__ident_func__函数获取,然后在__storage__字典中找到线程ident对应的结果集从获取到的结果中再查找age属性
设置local某属性时如:local.age = 12 实际触发的是__setattr__方法先获取到当前线程ID——__ident_func__函数获取,然后在__storage__字典设置相应的属性字典集
另一个__release_local__方法就是将相应的线程数据删除。
画个简图比较起来更直观一些。
主线程中生成一个对象local=Local(),三个线程中进行相同的操作local.no=每个线程对应的数。为每个线程都开辟一个存储,所以谁来取或者存就找到自己对应中的位置,虽然取得key都一样,但是每次存取都是只关于自己的值。
LocalStack
LocalStack也是定义在Flask所依赖的werkzeug库,从字面意思来理解,它就是Local的堆栈操作,看一下源码如何定义。
LocalStack实质就是围绕着Local来进行操作,根据上面我们读完Local的源码可以看到,
LocalStack定义了一个Local对象
给这个对象设置了一个stack属性,且这个属性是一个列表
LocalStack中定义了对这个列表进行压栈,出栈等方法
给类中的Local对象提供了自定义ident_func的方法
LocalProxy
LocalProxy字面意思就是做一个Local的代理,我们先从一个request的定义来看LocalProxy的用法,然后结合源码来看LocalProxy到底是用来做什么?
类中稍微有些难理解的就是关于object.__setattr__(self, “_LocalProxy__local”, local)的作用,实际就是给self设置一个__local属性。这是Python类中关于私有变量的定义。可以看Python的官方定义python私有变量。
可以看到这个类将所有Python类所内置的方法都进行重写,重写后所有的操作都是基于类中所定义的_get_current_object方法返回的对象进行操作。
而这个方法中返回值就是初始化时所给定的local对象执行返回的结果。如果创建时指定的不是Local对象,则直接执行此方法。如果给定的是Local对象,则根据类名查找对应的对象。
现在这个比较抽象,这个代理到底是做的什么? 我们结合Flask定义全局的request对象来看。假如我们想获取请求的方法是什么,那我们使用的就是request.method。
下面是request定义的源码
根据LocalProxy的源码中重写的__getattr__方法,先执行_get_current_object方法获取到对象,然后再获取返回对象method属性。
创建LocalProxy时传递的函数是_lookup_req_object的偏函数,实际就是_lookup_req_object且name=request
再LocalProxy中__local就是一个函数,所以在执行_get_current_object就是执行_lookup_req_object且name=request返回的值,然后再取其method属性
此时再执行_lookup_req_object函数,从_request_ctx_stack获取top的request
使用Proxy可以简单快捷的使用request.method获取相应的值,其核心就是每次获取时都会执行对应的函数,而函数中每次返回的值都是线程安全。保证数据正确且优雅。 否则我们每次都去执行一个函数来获取其值,然后再取其属性。
“Flask的上下文管理详解”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!