• Flask上下文


      在flask里的request和session的设置方式还是比较独特的,导入的这个两个东西给人感觉是全局变量,不像django,request是以参数方式传递,当然flask这种方式在单线程下,肯定是不会存在问题的,但是多线程了?

      试想这么一个场景:Alex先来设置了session,过一阵子再来取值,但是这段时间seven改掉了这个值,而Alex来取的值变成了seven设置的,这并不是我们想要的,那基于多线程下,你猜flask是怎么解决这个问题了?

    • 加锁,设置完后我先锁上,等下次用完再解锁
    • 给线程开辟单独的空间,用于保存这个

      如果是第一种方式,在执行效率上会大大折扣,所以猜测是第二种方式

      在深入研读flask源码前,我需要了解一下本地线程,它保证了即使是多线程的情况下,自己的值也是相互隔离的

    import threading
    
    local_values = threading.local()
    
    
    def func(num):
        local_values.name = num  #这个就是隔离的变量
        import time
        time.sleep(1)
        print(local_values.name, threading.current_thread().name)
    
    
    for i in range(20):
        th = threading.Thread(target=func, args=(i,), name='线程%s' % i)
        th.start()
    

       所以上面的threading.local对象,用于为每个线程开辟一块空间来保存它独有的值

      所以就有了以下几种情况下,解决方案:

    • 情况一:单进程单线程,基于全局变量来做
    • 情况二:单进程多线程,threading.local对象
    • 情况三:单进程单线程(多个协程),那这个threading.local对象也做不到

      对于情况三,由于协程是在线程里并发的,而threading.local对象只是对线程起作用,似乎用它对多协程不起作用,那说这里,如果要支持,就需要自定义了

      在存储上,可以用字典来存储,但我们需要获取线程或协程的唯一标识

    • 线程  from _thread import get_ident
    • 协程 from greenlet import getcurrent as get_ident
    """
    {
       1368:{}
    }
    
    
    
    """
    import threading
    try:
        from greenlet import getcurrent as get_ident # 协程
    except ImportError:
        try:
            from thread import get_ident
        except ImportError:
            from _thread import get_ident # 线程
    
    
    class Local(object):
        def __init__(self):
            self.storage = {}
            self.get_ident = get_ident
    
        def set(self,k,v):
            ident = self.get_ident()
            origin = self.storage.get(ident)
            if not origin:
                origin = {k:v}
            else:
                origin[k] = v
            self.storage[ident] = origin
    
        def get(self,k):
            ident = self.get_ident()
            origin = self.storage.get(ident)
            if not origin:
                return None
            return origin.get(k,None)
    
    local_values = Local()
    
    
    def task(num):
        local_values.set('name',num)
        import time
        time.sleep(1)
        print(local_values.get('name'), threading.current_thread().name)
    
    
    for i in range(20):
        th = threading.Thread(target=task, args=(i,),name='线程%s' % i)
        th.start()
    

       上面方式就能完美的解决协程了

      不过在上面的设置和获取,我们可以优化一下,那就要用到面向对象的知识了

    class Foo(object):
    
        def __init__(self):
            object.__setattr__(self, 'storage', {}) #这赋值方式就不会调用__setattr__
            # self.storage = {}  
    
        def __setattr__(self, key, value):
            # self.storage = {'k1':'v1'}  #在这里不能用这种方式,因为这个赋值过程就是在调用__setattr__,会陷入死循环
            print(key,value)
    
        def __getattr__(self, item):
            print(item)
            return 'df'
    
    
    obj = Foo()
    
    obj.x = 123  #调用__setattr__方法
    # 对象.xx   #调用__getattr__方法
    

       优化后的就和flask实现的源码一致了

    import threading
    try:
        from greenlet import getcurrent as get_ident # 协程
    except ImportError:
        try:
            from thread import get_ident
        except ImportError:
            from _thread import get_ident # 线程
    
    
    class Local(object):
    
        def __init__(self):
            object.__setattr__(self, '__storage__', {})
            object.__setattr__(self, '__ident_func__', get_ident)
    
    
        def __getattr__(self, name):
            try:
                return self.__storage__[self.__ident_func__()][name]
            except KeyError:
                raise AttributeError(name)
    
        def __setattr__(self, name, value):
            ident = self.__ident_func__()
            storage = self.__storage__
            try:
                storage[ident][name] = value
            except KeyError:
                storage[ident] = {name: value}
    
        def __delattr__(self, name):
            try:
                del self.__storage__[self.__ident_func__()][name]
            except KeyError:
                raise AttributeError(name)
    
    
    local_values = Local()
    
    
    def task(num):
        local_values.name = num
        import time
        time.sleep(1)
        print(local_values.name, threading.current_thread().name)
    
    
    for i in range(20):
        th = threading.Thread(target=task, args=(i,),name='线程%s' % i)
        th.start()
    
  • 相关阅读:
    网页布局 选择符 选择符权重
    css基础
    新手入门html 表格 表单 超链接 图片
    新手入门html
    批量安装Windows系统
    无人值守批量安装服务器
    PXE实现无人值守批量安装服务器
    小白必看:零基础安装Linux系统(超级详细)
    项目实战:rsync+sersync实现数据实时同步
    rsync学习笔记
  • 原文地址:https://www.cnblogs.com/xinsiwei18/p/9501601.html
Copyright © 2020-2023  润新知