通过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()

 

posted on 2019-07-18 20:29  小胖子方法  阅读(190)  评论(0编辑  收藏  举报

导航