zoukankan      html  css  js  c++  java
  • Flask源码关于local的实现

    flask源码关于local的实现

    try:
        # 协程
        from greenlet import getcurrent as get_ident
    except ImportError:
        try:
            from thread import get_ident    # 导入get_ident
        except ImportError:
            from _thread import get_ident
    """
    __storage__ = {
        1111:{"stack":[汪洋] }
    }
    """
    class Local(object):
    
        def __init__(self):
            # self.__storage__ = {}
            # self.__ident_func__ = get_ident
            object.__setattr__(self, "__storage__", {})
            object.__setattr__(self, "__ident_func__", get_ident)
    
        def __iter__(self):
            return iter(self.__storage__.items())
    
        def __release_local__(self):
            self.__storage__.pop(self.__ident_func__(), None)   # 由于get_ident是一个方法,当获取到这个对象之后需要加括号才能执行所以self.__ident_func__()
    
        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__() # 1111
            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)
    
    class LocalStack(object):
        def __init__(self):
            self._local = Local()
        def push(self, obj):
            """Pushes a new item to the stack"""
            # self._local.stack == getattr
            # rv = None
            rv = getattr(self._local, "stack", None)
            if rv is None:
                self._local.stack = rv = []
            rv.append(obj)
            return rv
    
        def pop(self):
            stack = getattr(self._local, "stack", None)
            if stack is None:
                return None
            elif len(stack) == 1:
                # release_local(self._local)
                # del __storage__[1111]
                return stack[-1]
            else:
                return stack.pop()
    
        @property
        def top(self):
            try:
                return self._local.stack[-1]
            except (AttributeError, IndexError):
                return None
    
    obj = LocalStack()
    obj.push('汪洋')
    obj.push('成说')
    
    print(obj.top)
    
    obj.pop()
    obj.pop()
    

    总结:

    在flask中有个local类,他和threading.local的功能一样,为每个线程开辟空间进行存取数据,他们两个的内部实现机制,内部维护一个字典,以线程(协程)ID为key,进行数据隔离,如:
        __storage__ = {
    		1211:{'k1':123}
        }
        
        obj = Local()
        obj.k1 = 123
        
    在flask中还有一个LocalStack的类,他内部会依赖local对象,local对象负责存储数据,localstack对象用于将local中的值维护成一个栈。
    	__storage__ = {
    		1211:{'stack':['k1',]}
        }
    
    	obj= LocalStack()
        obj.push('k1')
        obj.top
        obj.pop()
    

    7.flask源码中总共有2个localstack对象

    # context locals
    __storage__ = {
    	1111:{'stack':[RequestContext(reqeust,session),]},
        1123:{'stack':[RequestContext(reqeust,session),]},
    }
    _request_ctx_stack = LocalStack()
    
    
    __storage__ = {
    	1111:{'stack':[AppContenxt(app,g),]}
        1123:{'stack':[AppContenxt(app,g),]},
    }
    _app_ctx_stack = LocalStack()
    
    _request_ctx_stack.push('小魔方')
    _app_ctx_stack.push('大魔方')
    
    • 上下文管理
      • 请求上下文管理
      • 应用上下文管理

    解析

    1. 首先说请求上下文管理的设计思路:
    	* 当开启多线程或者协程去执行这个程序的时候,就需要对每个访问对象包装自己的数据,这样就不会发生数据的冲突,那么要怎么才能规避这个问题呢??
        * 利用threading.local的知识,根据相似的实现原理,设计这个上下文管理机制;
        * 首先写一个Local类,这个类中封装两个属性一个的属性值是一个空的字典,这个空字典的设计是这样的:字典中的键是当先执行的线程或者协程的id值,然后值是一个空的列表;
        *另一个是get_ident方法名,这个方法是获取可以获取到线程或者协程的id;这个的内部是将协程的模块名改成:get_ident了,所以你如果开的是线程就获取线程的id,如果是协程就获取协程的id;
         * 然后就是这个类中的实现方法了,有一个__setattr__方法,这个方法的作用主要是增加给__storage__这个字典中增加值的,__getattr__这个方法时获取这当前这线程或者协程值对应的id去__storage__获取对应的id的那个列表;
        * 还有一个清空当前线程或者协程保存的数据__release_local__,
    
  • 相关阅读:
    JVM学习记录-垃圾收集器
    JVM学习记录-垃圾回收算法
    Java设计模式学习记录-策略模式
    【转】Java方向如何准备技术面试答案(汇总版)
    Java设计模式学习记录-代理模式
    JVM之ParNew收集器
    JVM之CMS收集器
    动态代理:cgib、jdk、java javassist
    JVM之Class文件结构
    JAVA之直接内存(DirectMemory)
  • 原文地址:https://www.cnblogs.com/zhufanyu/p/11938097.html
Copyright © 2011-2022 走看看