• 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()
    
  • 相关阅读:
    圣战结束
    Linux_系统管理_网络配置_命令行配置网络
    Window下MySQL安装配置
    Linux_系统管理_根据进程名kill进程
    Windows下PHP安装配置
    Apache + PHP + MySql windows xp 安装设置
    visual studio 2008生成asp.net网站的问题?
    数据库抽象层PDO和ADOdb
    正则表达式修正符
    linux搭建SVN服务器
  • 原文地址:https://www.cnblogs.com/chanyuli/p/12057515.html
Copyright © 2020-2023  润新知