zoukankan      html  css  js  c++  java
  • Flask补充--threading.local对象

    在Flask请求上下文中,我们发现Flask中current_app, g这两个对象以及request,session这两个对象,在整个Flask生命周期中,都只是一个对象,那当请求过来的时候,是怎么区分是哪个用户的呢?

    current_app = LocalProxy(_find_app)
    request = LocalProxy(partial(_lookup_req_object, 'request'))
    session = LocalProxy(partial(_lookup_req_object, 'session'))
    g = LocalProxy(partial(_lookup_app_object, 'g'))
    

    这里面主要用到了一个线程里面的Local对象以及偏函数partial

    Local

    在使用threading.local()之前,先了解一下局部变量和全局变量。

    局部变量

    import threading
    import time
    
    def foo():
        x = 0
        for i in range(100):
            time.sleep(0.0001)
            x += 1
    
        print(threading.current_thread(), x)
    
    
    for i in range(5):
        threading.Thread(target=foo).start()
        
    """
    运行结果:
    <Thread(Thread-5, started 21732)> 100
    <Thread(Thread-1, started 13300)> 100
    <Thread(Thread-4, started 1568)> 100
    <Thread(Thread-2, started 19864)> 100
    <Thread(Thread-3, started 23984)> 100
    """
    

    上面例子使用多线程,每个子线程完成不同的计算任务,x是局部变量。

    每个子线程都要压栈,每个栈是独立的空间。每次压栈,局部变量x的作用域地址是不同的(线程独享),计算结果互不干扰。

    全局变量

    import threading
    import time
    
    x = 0
    
    def foo():
        global x
        x = 0
        for i in range(100):
            time.sleep(0.0001)
            x += 1
    
        print(threading.current_thread(), x)
    
    
    for i in range(5):
        threading.Thread(target=foo).start()
        
    """
    运行结果:
    <Thread(Thread-1, started 19492)> 491
    <Thread(Thread-3, started 22692)> 497
    <Thread(Thread-5, started 24344)> 498
    <Thread(Thread-2, started 24428)> 499
    <Thread(Thread-4, started 19000)> 500
    """
    

    上面例子中当主线程中x是全局变量时,就变成了公共资源(也就是同一个对象),每个子线程互相干扰,最终导致错误的计算结果。

    Python提供了 threading.local 类,将这个类实例化得到一个全局对象,但是不同的线程使用这个对象存储的数据其它线程不可见(本质上就是不同的线程使用这个对象时为其创建一个独立的字典)。

    使用threading.local()

    import threading
    import time
    
    loc = threading.local()
    
    def foo():
        loc.x = 0
        for i in range(100):
            time.sleep(0.0001)
            loc.x += 1
    
        print(threading.current_thread(), loc.x)
    
    
    for i in range(5):
        threading.Thread(target=foo).start()
        
    """
    运行结果:
    <Thread(Thread-1, started 20008)> 100
    <Thread(Thread-2, started 23644)> 100
    <Thread(Thread-5, started 10396)> 100
    <Thread(Thread-4, started 22280)> 100
    <Thread(Thread-3, started 19980)> 100
    """
    

    每个子线程使用全局对象loc,但每个线程定义的属性loc.x是该线程独有的。

    举一个错误的例子:,主线程中使用threading.local定义本地变量x,x在主线程中是独有的,子线程中就访问不到主线程的x的属性。

    import threading
     
    X='abc'
    ctx=threading.local()
    ctx.x=123 #主线程中定义x本地属性
    print(ctx,type(ctx),ctx.x)
     
    def work():
        print(X)
        print(ctx)
        print(ctx.x) #子线程访问不到
        print('Good job')
     
    threading.Thread(target=work).start()
    
    """
    运行结果:
    <_thread._local object at 0x000001B22BBAB780> <class '_thread._local'> 123
    abc
    <_thread._local object at 0x000001B22BBAB780>
    Exception in thread Thread-1:
    Traceback (most recent call last):
      File "E:/Python学习笔记/flask/123.py", line 13, in work
        print(ctx.x)  # 子线程访问不到
    AttributeError: '_thread._local' object has no attribute 'x'
    """
    

    ctx全局对象对主线程和子线程都是可以使用的,主线程定义了属性x,但子线程在尝试访问属性x时,就相当于访问自己线程内的属性x,而自己线程并没有定义,就会抛出AttributeError异常:'_thread._local' object has no attribute 'x'

    自定义threading.local

    函数版

    from threading import get_ident, Thread
    import time
    
    # 定义一个全局字典
    storage = {}
    
    def set(k, v):
        ident = get_ident()
        # print(ident)
        if ident in storage:
            storage[ident][k] = v
        else:
            storage[ident] = {k: v}
    
    def get(k):
        ident = get_ident()
        # print(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()
    
    print(storage) 
    """
    {
        20552: {'val': 0}, 
        18496: {'val': 1}, 
        24476: {'val': 2}, 
        18700: {'val': 3}, 
        23740: {'val': 4}, 
        22160: {'val': 5}, 
        23896: {'val': 6}, 
        19204: {'val': 7}, 
        19028: {'val': 8}, 
        17972: {'val': 9}
    }
    """
    

    面向对象版

    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()
        
    print(Local.storage)
    """
    {
    	19296: {'val': 0}, 
    	20436: {'val': 1}, 
    	8240: {'val': 2}, 
    	19668: {'val': 3}, 
    	16932: {'val': 4}
    }
    """
    

    通过setattr和getattr实现

    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()
    def task(arg):
        obj.val = arg
        print(obj.val)
        
    for i in range(10):
        t = Thread(target=task,args=(i,))
        t.start()
    

    每个对象有自己的存储空间(字典)

    from threading import get_ident, Thread
    import time
    
    
    class Local(object):
    
        def __init__(self):
            object.__setattr__(self, 'storage', {})
            # print(1, self.__dict__)
            # self.aaa = {}
            # print(self.__dict__)
    
        def __setattr__(self, k, v):
            # print(k, v, '>>>')
            ident = get_ident()
            # print(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()
    # print(2, obj.__dict__)
    
    
    def task(arg):
        obj.val = arg
        obj.xxx = arg
        print(obj.val)
        # print(obj.__dict__)
    
    
    for i in range(10):
        t = Thread(target=task, args=(i,))
        t.start()
    
  • 相关阅读:
    Save the problem!
    Divisiblity of Differences
    定个小目标
    Faulty Robot
    反片语 uva 156(map的使用
    Input is terminated by EOF.
    uva10815 andy的字典(set的应用)
    uva-101 搬砖问题(不定长数组vector的使用)
    回文串uva401(清简出风尘)
    WERTYU (善用常量数组
  • 原文地址:https://www.cnblogs.com/Hades123/p/11779686.html
Copyright © 2011-2022 走看看