flask中间件和LOCAL对象
中间件
我们知道 app.run()之后,会调用__call__()方法,看一下他的源码
def __call__(self, environ, start_response): """The WSGI server calls the Flask application object as the WSGI application. This calls :meth:`wsgi_app` which can be wrapped to applying middleware.""" return self.wsgi_app(environ, start_response)
就这么多,这里的self就是我们的app,一旦调用了app的wsgi_app方法,我们就不能插足了,所以中间件要在调用这个之前写。怎么实现呢,就是
from flask import Flask,flash,get_flashed_messages,request app = Flask(__name__) class MyMiddleware: def __init__(self,wsgi_app): #实例化对象的时候就会走这个方法,传进来的wsgi_app是原生的,复制给了对象的属性 self.wsgi_app=wsgi_app #类的__call__,对象加括号的时候会调用,在上面的源码里,就是self.wsgi_app(environ, start_response),这里的self.wsgi_app是MyMiddleware类的对象,所以会执行这里的__Call__ def __call__(self, environ, start_response): #自己想要通过中间件实现的功能就可以写在这里了。 print("123") res=self.wsgi_app(environ, start_response) print("456") print(res) return res @app.route('/index') def index(): # request.method # session['sd'] return "ssdsdsdfsd" if __name__ == '__main__': #代码从这里开始走,先实例化一个自己生成的类的对象,把原来的app.wsgi_app当做参数传给类的__init__,生成的对象赋值给新的app.wsgi_app app.wsgi_app = MyMiddleware(app.wsgi_app) app.run()
LOCAL对象
我们在使用多线程的时候会有一个问题,那就是数据不安全问题
from threading import Thread import time cxw = -1 def task(arg): global cxw cxw = arg time.sleep(2) print(cxw) for i in range(10): t = Thread(target=task,args=(i,)) t.start()
打印结果发现,所有的cxw都是9,按照我们原来的想法结果应该是0123456789这样,但是睡了两秒之后,最后一个线程早就把cxw变成9了。
通常解决这种问题我们会使用线程锁,但是也可以用local来实现
导入的local from threading import Thread from threading import local import time # 特殊的对象 cxw = local() def task(arg): # 对象.val = 1/2/3/4/5 cxw.value = arg time.sleep(2) print(cxw.value) for i in range(10): t = Thread(target=task,args=(i,)) t.start()
这时候打印出来的内容就是正确的了,但不一定是按顺序的(cpu的调度问题)。那么这个到底是怎么实现的。
原理是类似于字典一样的存取值方式。获取当前的线程的id,来存入对应的值,取的时候也是同样,根据线程的id值来取,这样就实现了。
from threading import get_ident,Thread import time storage = {} def set(k,v): #获取当前线程的id ident = get_ident() #判断当前这个线程的id存不存在于这个storage,存在的话就设置一个值 if ident in storage: #这里设置完之后结果类似于 {"pid1号":{k:v},} storage[ident][k] = v else: #不存在这个pid号的话,就设置一个 storage[ident] = {k:v} for i in range(10): t = Thread(target=task,args=(i,)) t.start()
面向对象的形式:
面向对象的形式 from threading import get_ident,Thread import time class Local(object): storage = {} def set(self, k, v): ident = get_ident() if ident in Local.storage: Local.storage[ident][k] = v else: Local.storage[ident] = {k: v} def get(self, k): ident = get_ident() return Local.storage[ident][k] obj = Local() def task(arg): obj.set('val',arg) v = obj.get('val') print(v) for i in range(10): t = Thread(target=task,args=(i,)) t.start()
以上版本均有问题,以下才是最终版
最终版:
try: #不仅可以实现多线程,还可以实现协程 from greenlet import getcurrent as get_ident except Exception as e: from threading import get_ident from threading import Thread # from threading import get_ident,Thread import time class Local(object): #为什么要把初始化strorage的语句放在__init__里面,也就是说把它变为对象的属性,而不是类的属性,因为一个项目可能在别的地方也会调用 Local,这时候大家用的就是共同的storage了,所以要把它设置为对象的属性 def __init__(self): #为什么这里要调用功父类的__setattr__?因为如果直接用self.storage={}的话,会调用__setattr__,在自己的__setattr__里面的self.storage会调用__getattr_,然后在__getattr__中会发生递归,不停地调用自己。所以这里要调用父类的__setattr__,就像我们以前正常的赋值(dic['a']=1)一样。 object.__setattr__(self,'storage',{}) #self.storage={} def __setattr__(self, k, v): ident = get_ident() if ident in self.storage: self.storage[ident][k] = v else: self.storage[ident] = {k: v} def __getattr__(self, k): ident = get_ident() return self.storage[ident][k] obj = Local() def task(arg): obj.val = arg obj.xxx = arg print(obj.val) for i in range(10): t = Thread(target=task,args=(i,)) t.start()
相关推荐
bestallen 2020-08-17
JessePinkmen 2020-07-26
washing 2020-07-18
hzyuhz 2020-07-04
hzyuhz 2020-06-28
hzyuhz 2020-06-25
苦咖啡flask 2020-06-25
苦咖啡flask 2020-06-25
苦咖啡flask 2020-06-18
washing 2020-06-16
liuweiq 2020-06-14
wushaojun 2020-06-14
JessePinkmen 2020-06-14
kgshuo 2020-06-14
JessePinkmen 2020-06-14
bestallen 2020-06-13