zoukankan      html  css  js  c++  java
  • 通过local对象的使用,分析flask中全局request对象为神魔不同的视图函数中不会混乱--协助解读flask的源码

    问题::fask的request是全局的,为神魔每个视图函数都是用request,却没有造成request中数据错乱的现象??

    # 不用local, 开启10个线程同时对全局的wzg修改,这种情况下,我看一下执行的结果会是怎样?
    from threading import Thread
    import time
    wzg = -1
    def task(arg):
        global wzg
    
        wzg = arg
        # 阻塞一会,线程该值完毕,哪一个线程执行最后的到执行权,结果就会修改全局wzg,其他线程对结果的修改就会被篡改,所以结果全都一样
        time.sleep(2)
        print(wzg)
    
    for i in range(10):
        t = Thread(target=task,args=(i,))
        t.start()
    '''
    #结果全部为9,所以其他线程对wzg的修改被篡改,
    造成这个情况的原因是:
    多个线程同时操作全局里的同一个变量wzg,没有任何标记可以区分那个线程修改了什么,最后执行的线程会将前面其他线程修改的值全都次修该的值,造成结果的错乱
    所以打印的结果也是最后线程修改的值
    flask中的request,session也是全局变量,为神魔每个视图用的request不会乱?
    这里先看一下local对象的使用
    '''
    #使用local对象
    from threading import Thread
    from threading import local
    '''
    根据线程进行区分,相当于这种存储方式{'线程id1':{'args':1},'线程id2':{'args':2},'线程id3':{'args':3}}
    这样打印出来的就是对应线程的值,这样就可以防止数据错乱
    # # {arg:1}
    '''
    import time
    lqz = local()
    def task(arg):
        lqz.arg = arg
        time.sleep(2)
        print(lqz.arg)
    
    for i in range(10):
        t = Thread(target=task,args=(i,))
        t.start()
    #自定义local,函数版
    from threading import get_ident,Thread  #get_ident线程的ID号
    import time
    storage = {}
    def set(k,v):
        #获取线程的id号
        # storage={'线程id1': {'args': 1}, '线程id2': {'args': 2}, '线程id3': {'args': 3}}
        #这样子存起来的值就对应各自的线程
        ident = get_ident()
        print(ident)
        if ident in storage:
            storage[ident][k] = v
        else:
            storage[ident] = {k:v}
    def get(k):
        ident = get_ident()
        return storage[ident][k]
    def task(arg):
        set('val',arg)
        v = get('val')
        print(v)
    
    for i in range(10):
        t = Thread(target=task,args=(i,))
        t.start()
    #面向对象版的local
    from threading import get_ident,Thread
    import time
    #{'线程id1': {'args': 1}, '线程id2': {'args': 2}, '线程id3': {'args': 3}}
    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')
        time.sleep(1)
        print(v)
    for i in range(10):
        t = Thread(target=task,args=(i,))
        t.start()
    #改进版本1
    from threading import get_ident,Thread
    import time
    class Local(object):
        storage = {}
        def __setattr__(self, k, v):
            ident = get_ident()
            if ident in Local.storage:
                Local.storage[ident][k] = v
            else:
                Local.storage[ident] = {k: v}
        def __getattr__(self, k):
            ident = get_ident()
            return Local.storage[ident][k]
    obj = Local()
    # obj2=Local()  #谢谢对象用的都是同一个字典
    # obj3=Local()
    # obj4=Local()
    # obj5=Local()
    def task(arg):
        obj.val = arg
        time.sleep(1)
        print(obj.val)
    for i in range(10):
        t = Thread(target=task,args=(i,))
        t.start()
    上面那个用的全是类的字典,不管生成几个对象,用的都是同一个,也有可能造成数据错乱
    所以我们希望每次生成local对象用的都是自己的字典,所以对上面的继续改进2
    改进版2
    from
    threading import get_ident,Thread import time class Local(object): def __init__(self): #将字典放在init中,这样每个对象用的都是自己的字典,但是要注意黄色部分的写法会出现一直递归,报错, object.__setattr__(self,'storage',{}) #这里直接调用父类的__setattr__方法 #这样写会出现递归,该出调用__setattr__,se # 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 time.sleep(1) print(obj.val) for i in range(10): t = Thread(target=task,args=(i,)) t.start() 到此为止,自己写了一个local对象,只支持线程
    #改进版3即支持协程又支持线程
    try:
        #getcurrent 获取协程id
        from greenlet import getcurrent as get_ident
    except Exception as e:
        from threading import get_ident
    from threading import Thread
    import time
    class Local(object):
        def __init__(self):
            object.__setattr__(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()
  • 相关阅读:
    9011,9012,9013,9014,8050,8550三极管的区别
    XP制动关机CMD命令
    搭建系统框架发现的三个Web.Config问题
    监听公众号返回按钮,直接退出到公众号页面
    微信公众号h5页面自定义分享
    博客园页面设置
    js 中加减乘除 比较精确的算法,js本身有些运算会出错,这里给出较精确的算法
    HTML属性
    HTML属性
    处理ajax数据;数据渲染(细节)
  • 原文地址:https://www.cnblogs.com/Hale-wang/p/11209795.html
Copyright © 2011-2022 走看看