• Flask的上下文管理:Werkzeug库的local模块


    1、协程greenlet

    from greenlet import greenlet
    from greenlet import getcurrent
    def t1():
        print(12,getcurrent())
        gr2.switch()
        print(34,getcurrent())
        gr2.switch()
    def t2():
        print(56,getcurrent())
        gr1.switch()
        print(78,getcurrent())
    
    gr1 = greenlet(t1) #启动一个携程
    gr2 = greenlet(t2)
    gr1.switch()

      这里创建了两个greenlet协程对象,gr1和gr2,分别对应于函数test1()和test2()。使用greenlet对象的switch()方法,即可以切换协程。上例中,我们先调用”gr1.switch()”,函数test1()被执行,然后打印出”12″;接着由于”gr2.switch()”被调用,协程切换到函数test2(),打印出”56″;之后”gr1.switch()”又被调用,所以又切换到函数test1()。但注意,由于之前test1()已经执行到第5行,也就是”gr2.switch()”,所以切换回来后会继续往下执行,也就是打印”34″;现在函数test1()退出,同时程序退出。由于再没有”gr2.switch()”来切换至函数test2(),所以程序第11行”print 78″不会被执行。

      getcurrent()用来获取协程的id。

    2、使用greenlet实现为每个协程开辟数据存储空间

    2.1、为每个协程开辟数据存储空间

      源码:

    from greenlet import getcurrent as get_ident
    from greenlet import greenlet
    
    # 释放Local类实例化对象local中该协程存储在local.__storage__中key为self.__ident_func__()的数据
    def release_local(local):
        local.__release_local__()
    
    class Local(object):
    
        __slots__ = ('__storage__', '__ident_func__')
    
        def __init__(self):
            # 设置类Local的对象l的属性__storage__为空字典
            object.__setattr__(self, '__storage__', {})
            # 设置类Local的对象l的属性__ident_func__为get_ident方法,get_ident()可以获取协程的id号
            object.__setattr__(self, '__ident_func__', get_ident)
    
        # 将类Local对象l内所有协程的数据生成一个生成器返回
        def __iter__(self):
            return iter(self.__storage__.items())
    
        # 释放该协程中存储的数据空间
        def __release_local__(self):
            self.__storage__.pop(self.__ident_func__(), None)
    
        # 获取该协程中存储的key为name的数据
        def __getattr__(self, name):
            try:
                return self.__storage__[self.__ident_func__()][name]
            except KeyError:
                raise AttributeError(name)
    
        # 将name作为key,value作为value存入该协程中的数据空间中
        def __setattr__(self, name, value):
            ident = self.__ident_func__()
            storage = self.__storage__
            try:
                storage[ident][name] = value
            except KeyError:
                storage[ident] = {name: value}
    
        # 删除该协程中存储的key为name的数据
        def __delattr__(self, name):
            try:
                del self.__storage__[self.__ident_func__()][name]
            except KeyError:
                raise AttributeError(name)
    
    l = Local()
    
    def t1():
        # 将数据a=1 ,A=3存入协程gr1中
        l.a = 1
        l.A = 3
        print("协程a:%s" % get_ident(), l.a)
        gr2.switch()
    
    def t2():
        # 将数据b=2 ,B=4存入协程gr2中
        l.b = 2
        l.B = 4
        print("协程b:%s" % get_ident(), l.b)
        gr1.switch()
    
    # 将数据m=8 ,M=8存入默认生成的协程中(可以看做主协程)
    l.m = 8
    l.M = 8
    print("协程m:%s" % get_ident(),l.m)
    gr1 = greenlet(t1) #启动一个协程
    gr2 = greenlet(t2)
    gr1.switch()
    
    print("协程m:%s" % get_ident(), l.m)
    for k,v in l.__storage__.items():
        print("%s:%s"%(k,v))

      执行结果:

    协程m:<greenlet.greenlet object at 0x01E25558> 8
    协程a:<greenlet.greenlet object at 0x01E25500> 1
    协程b:<greenlet.greenlet object at 0x01E25BE0> 2
    协程m:<greenlet.greenlet object at 0x01E25558> 8
    <greenlet.greenlet object at 0x01E25558>:{'m': 8, 'M': 8}
    <greenlet.greenlet object at 0x01E25500>:{'a': 1, 'A': 3}
    <greenlet.greenlet object at 0x01E25BE0>:{'b': 2, 'B': 4}
    

    2.2、在协程执行完后释放数据存储空间

      源码:

    from greenlet import getcurrent as get_ident
    from greenlet import greenlet
    
    # 释放Local类实例化对象local中该协程存储在local.__storage__中key为self.__ident_func__()的数据
    def release_local(local):
        local.__release_local__()
    
    class Local(object):
    
        __slots__ = ('__storage__', '__ident_func__')
    
        def __init__(self):
            # 设置类Local的对象l的属性__storage__为空字典
            object.__setattr__(self, '__storage__', {})
            # 设置类Local的对象l的属性__ident_func__为get_ident方法,get_ident()可以获取协程的id号
            object.__setattr__(self, '__ident_func__', get_ident)
    
        # 将类Local对象l内所有协程的数据生成一个生成器返回
        def __iter__(self):
            return iter(self.__storage__.items())
    
        # 释放该协程中存储的数据空间
        def __release_local__(self):
            self.__storage__.pop(self.__ident_func__(), None)
    
        # 获取该协程中存储的key为name的数据
        def __getattr__(self, name):
            try:
                return self.__storage__[self.__ident_func__()][name]
            except KeyError:
                raise AttributeError(name)
    
        # 将name作为key,value作为value存入该协程中的数据空间中
        def __setattr__(self, name, value):
            ident = self.__ident_func__()
            storage = self.__storage__
            try:
                storage[ident][name] = value
            except KeyError:
                storage[ident] = {name: value}
    
        # 删除该协程中存储的key为name的数据
        def __delattr__(self, name):
            try:
                del self.__storage__[self.__ident_func__()][name]
            except KeyError:
                raise AttributeError(name)
    
    l = Local()
    
    
    def t1():
        l.a = 1
        l.A = 3
        print("协程a:%s" % get_ident(), l.a)
        gr2.switch()
        release_local(l)
        print("协程a:%s||是否有l.a:" % get_ident(), hasattr(l, 'a'))
        gr2.switch()
    
    def t2():
        l.b = 2
        l.B = 4
        print("协程b:%s" % get_ident(), l.b)
        gr1.switch()
        release_local(l)
        print("协程b:%s||是否有l.b:" % get_ident(), hasattr(l, 'b'))
    
    
    # 将数据m=8 ,M=8存入默认生成的协程中(可以看做主协程)
    l.m = 8
    l.M = 8
    print("协程m:%s" % get_ident(),l.m)
    gr1 = greenlet(t1) #启动一个协程
    gr2 = greenlet(t2)
    gr1.switch()
    
    print("协程m:%s" % get_ident(), l.m)
    for k,v in l.__storage__.items():
        print("%s:%s" % (k, v))

      执行结果:

    协程m:<greenlet.greenlet object at 0x00635608> 8
    协程a:<greenlet.greenlet object at 0x006355B0> 1
    协程b:<greenlet.greenlet object at 0x00635558> 2
    协程a:<greenlet.greenlet object at 0x006355B0>||是否有l.a: False
    协程b:<greenlet.greenlet object at 0x00635558>||是否有l.b: False
    协程m:<greenlet.greenlet object at 0x00635608> 8
    <greenlet.greenlet object at 0x00635608>:{'m': 8, 'M': 8}
    

     3、线程_thread

      Python3 线程中常用的两个模块为:

    • _thread
    • threading(推荐使用)

      thread 模块已被废弃。用户可以使用 threading 模块代替。所以,在 Python3 中不能再使用"thread" 模块。为了兼容性,Python3 将 thread 重命名为 "_thread"。

      源码:

    import _thread
    from _thread import get_ident
    from time import sleep
    
    def run(n):
        print("子线程:%s --id: %s"%(n,get_ident()))
    
    def main():
        _thread.start_new_thread(run, ("t1",))
        _thread.start_new_thread(run, ("t2",))
    
    if __name__ == "__main__":
        main()
        sleep(2)
        print("主线程 --id: %s" % ( get_ident()))

      执行结果:

    子线程:t2 --id: 5452
    子线程:t1 --id: 10488
    主线程 --id: 9804
    

    4、使用_thread实现为每个线程开辟数据存储空间

    4.1、为每个线程开辟数据存储空间

      源码:

    from _thread import get_ident,start_new_thread
    from time import sleep
    
    # 释放Local类实例化对象local中该线程存储在local.__storage__中key为self.__ident_func__()的数据
    def release_local(local):
        local.__release_local__()
    
    class Local(object):
    
        __slots__ = ('__storage__', '__ident_func__')
    
        def __init__(self):
            # 设置类Local的对象l的属性__storage__为空字典
            object.__setattr__(self, '__storage__', {})
            # 设置类Local的对象l的属性__ident_func__为get_ident方法,get_ident()可以获取线程的id号
            object.__setattr__(self, '__ident_func__', get_ident)
    
        # 将类Local对象l内所有线程的数据生成一个生成器返回
        def __iter__(self):
            return iter(self.__storage__.items())
    
        # 释放该线程中存储的数据空间
        def __release_local__(self):
            self.__storage__.pop(self.__ident_func__(), None)
    
        # 获取该线程中存储的key为name的数据
        def __getattr__(self, name):
            try:
                return self.__storage__[self.__ident_func__()][name]
            except KeyError:
                raise AttributeError(name)
    
        # 将name作为key,value作为value存入该线程中的数据空间中
        def __setattr__(self, name, value):
            ident = self.__ident_func__()
            storage = self.__storage__
            try:
                storage[ident][name] = value
            except KeyError:
                storage[ident] = {name: value}
    
        # 删除该线程中存储的key为name的数据
        def __delattr__(self, name):
            try:
                del self.__storage__[self.__ident_func__()][name]
            except KeyError:
                raise AttributeError(name)
    
    l = Local()
    
    def t1():
        # 将数据a=1 ,A=3存入当前线程中
        l.a = 1
        l.A = 3
        print("线程a:%s" % get_ident(), l.a)
        print("l.__storage__:",l.__storage__)
    
    def t2():
        # 将数据b=2 ,B=4存入当前线程中
        l.b = 2
        l.B = 4
        print("线程b:%s" % get_ident(), l.b)
        print("l.__storage__:",l.__storage__)
    
    
    def main():
        # 将数据m=8 ,M=8存入默认生成的线程中(可以看做主线程)
        print("l.__storage__:", l.__storage__)
        l.m = 8
        l.M = 8
        print("l.__storage__:", l.__storage__)
        print("线程m:%s" % get_ident(),l.m)
        start_new_thread(t1, ())
        start_new_thread(t2, ())
        sleep(5)
        print("线程m:%s" % get_ident(), l.m)
        print("l.__storage__:", l.__storage__)
    
    if __name__ == "__main__":
        main()

      执行结果:

    l.__storage__: {}
    l.__storage__: {12548: {'m': 8, 'M': 8}}
    线程m:12548 8
    线程a:10656 1
    l.__storage__: {12548: {'m': 8, 'M': 8}, 10656: {'a': 1, 'A': 3}}
    线程b:11564 2
    l.__storage__: {12548: {'m': 8, 'M': 8}, 10656: {'a': 1, 'A': 3}, 11564: {'b': 2, 'B': 4}}
    线程m:12548 8
    l.__storage__: {12548: {'m': 8, 'M': 8}, 10656: {'a': 1, 'A': 3}, 11564: {'b': 2, 'B': 4}}

    4.2、在线程执行完后释放数据存储空间

      源码:

    from _thread import get_ident,start_new_thread
    from time import sleep
    
    # 释放Local类实例化对象local中该线程存储在local.__storage__中key为self.__ident_func__()的数据
    def release_local(local):
        local.__release_local__()
    
    class Local(object):
    
        __slots__ = ('__storage__', '__ident_func__')
    
        def __init__(self):
            # 设置类Local的对象l的属性__storage__为空字典
            object.__setattr__(self, '__storage__', {})
            # 设置类Local的对象l的属性__ident_func__为get_ident方法,get_ident()可以获取线程的id号
            object.__setattr__(self, '__ident_func__', get_ident)
    
        # 将类Local对象l内所有线程的数据生成一个生成器返回
        def __iter__(self):
            return iter(self.__storage__.items())
    
        # 释放该线程中存储的数据空间
        def __release_local__(self):
            self.__storage__.pop(self.__ident_func__(), None)
    
        # 获取该线程中存储的key为name的数据
        def __getattr__(self, name):
            try:
                return self.__storage__[self.__ident_func__()][name]
            except KeyError:
                raise AttributeError(name)
    
        # 将name作为key,value作为value存入该线程中的数据空间中
        def __setattr__(self, name, value):
            ident = self.__ident_func__()
            storage = self.__storage__
            try:
                storage[ident][name] = value
            except KeyError:
                storage[ident] = {name: value}
    
        # 删除该线程中存储的key为name的数据
        def __delattr__(self, name):
            try:
                del self.__storage__[self.__ident_func__()][name]
            except KeyError:
                raise AttributeError(name)
    
    l = Local()
    
    def t1():
        # 将数据a=1 ,A=3存入当前线程中
        l.a = 1
        l.A = 3
        print("线程a:%s" % get_ident(), l.a)
        print("l.__storage__:",l.__storage__)
        release_local(l)
        print("释放后l.__storage__:",l.__storage__)
    
    def t2():
        # 将数据b=2 ,B=4存入当前线程中
        l.b = 2
        l.B = 4
        print("线程b:%s" % get_ident(), l.b)
        print("l.__storage__:",l.__storage__)
        release_local(l)
        print("释放后l.__storage__:", l.__storage__)
    
    
    def main():
        # 将数据m=8 ,M=8存入默认生成的线程中(可以看做主线程)
        print("l.__storage__:", l.__storage__)
        l.m = 8
        l.M = 8
        print("l.__storage__:", l.__storage__)
        print("线程m:%s" % get_ident(),l.m)
        start_new_thread(t1, ())
        start_new_thread(t2, ())
        sleep(5)
        print("线程m:%s" % get_ident(), l.m)
        print("l.__storage__:", l.__storage__)
    
    if __name__ == "__main__":
        main()
    

      执行结果:

    l.__storage__: {}
    l.__storage__: {11480: {'m': 8, 'M': 8}}
    线程m:11480 8
    线程b:12560 2
    l.__storage__: {11480: {'m': 8, 'M': 8}, 12560: {'b': 2, 'B': 4}}
    释放后l.__storage__: {11480: {'m': 8, 'M': 8}}
    线程a:7628 1
    l.__storage__: {11480: {'m': 8, 'M': 8}, 7628: {'a': 1, 'A': 3}}
    释放后l.__storage__: {11480: {'m': 8, 'M': 8}}
    线程m:11480 8
    l.__storage__: {11480: {'m': 8, 'M': 8}}
    

    5、LocalStack类

      LocalStack中封装了Local对象。LocalStack用来管理Locall对象,并提供push,pop方法,用来在当前线程或协程中存储数据、提取数据。

    class LocalStack(object):
    
        """This class works similar to a :class:`Local` but keeps a stack
        of objects instead.  This is best explained with an example::
    
            >>> ls = LocalStack()
            >>> ls.push(42)
            >>> ls.top
            42
            >>> ls.push(23)
            >>> ls.top
            23
            >>> ls.pop()
            23
            >>> ls.top
            42
    
        They can be force released by using a :class:`LocalManager` or with
        the :func:`release_local` function but the correct way is to pop the
        item from the stack after using.  When the stack is empty it will
        no longer be bound to the current context (and as such released).
    
        By calling the stack without arguments it returns a proxy that resolves to
        the topmost item on the stack.
    
        .. versionadded:: 0.6.1
        """
    
        def __init__(self):
            # 实例化一个Local()对象
            self._local = Local()
    
        # 释放当前线程或协程的数据存储空间
        def __release_local__(self):
            self._local.__release_local__()
    
        # 获取当前线程或协程的__ident_func__属性
        def _get__ident_func__(self):
            return self._local.__ident_func__
    
        # 设置当前线程或协程的__ident_func__属性
        def _set__ident_func__(self, value):
            object.__setattr__(self._local, '__ident_func__', value)
        __ident_func__ = property(_get__ident_func__, _set__ident_func__)
        del _get__ident_func__, _set__ident_func__
    
        def __call__(self):
            def _lookup():
                rv = self.top
                if rv is None:
                    raise RuntimeError('object unbound')
                return rv
            return LocalProxy(_lookup)
    
        # 将obj存入当前线程或协程的数据存储空间中以stack作为key的字典中
        def push(self, obj):
            """Pushes a new item to the stack"""
            rv = getattr(self._local, 'stack', None)
            if rv is None:
                self._local.stack = rv = []
            rv.append(obj)
            return rv
    
        # 对当前线程或协程的数据存储空间将以stack作为key的字典pop出一个数据,
        # 如果总数据长度为1,释放线程或协程的数据存储空间
        def pop(self):
            """Removes the topmost item from the stack, will return the
            old value or `None` if the stack was already empty.
            """
            stack = getattr(self._local, 'stack', None)
            if stack is None:
                return None
            elif len(stack) == 1:
                release_local(self._local)
                return stack[-1]
            else:
                return stack.pop()
    
        # 对当前线程或协程的数据存储空间将以stack作为key的字典中最顶端的数据
        @property
        def top(self):
            """The topmost item on the stack.  If the stack is empty,
            `None` is returned.
            """
            try:
                return self._local.stack[-1]
            except (AttributeError, IndexError):
                return None
    

    5.1、LocalStack的使用

      源码:

    from greenlet import greenlet
    from werkzeug.local import LocalStack
    
    ls = LocalStack()
    
    # 打印ls._local中存储的数据
    def get_datas(ls):
        for k, v in ls._local:
            print("%s:%s" % (k, v))
    
    def t1():
        # 将数据1, 3存入协程gr1中
        ls.push(1)
        ls.push(3)
        print("协程gr1添加后:")
        get_datas(ls)
        gr2.switch()
        ret = ls.pop()
        print("协程gr1释放:%s"%ret)
        print("协程gr1释放后:")
        get_datas(ls)
        print("协程gr1获取top:",ls.top)
        gr2.switch()
    
    def t2():
        # 将数据2, 4存入协程gr2中
        ls.push(2)
        ls.push(4)
        print("gr2添加后:")
        get_datas(ls)
        gr1.switch()
        ret = ls.pop()
        print("协程gr2释放:%s" % ret)
        print("协程gr2释放后:")
        get_datas(ls)
        print("协程gr2获取top:", ls.top)
    
    # 将数据8, 8存入默认生成的协程中(可以看做主协程)
    ls.push(8)
    ls.push(18)
    print("协程m添加后:")
    get_datas(ls)
    gr1 = greenlet(t1) #启动一个协程
    gr2 = greenlet(t2)
    gr1.switch()
    print("协程m:")
    get_datas(ls)
    

      执行结果:

    协程m添加后:
    <greenlet.greenlet object at 0x005D4A28>:{'stack': [8, 18]}
    协程gr1添加后:
    <greenlet.greenlet object at 0x005D4A28>:{'stack': [8, 18]}
    <greenlet.greenlet object at 0x005DF298>:{'stack': [1, 3]}
    gr2添加后:
    <greenlet.greenlet object at 0x005D4A28>:{'stack': [8, 18]}
    <greenlet.greenlet object at 0x005DF298>:{'stack': [1, 3]}
    <greenlet.greenlet object at 0x0061F1E8>:{'stack': [2, 4]}
    协程gr1释放:3
    协程gr1释放后:
    <greenlet.greenlet object at 0x005D4A28>:{'stack': [8, 18]}
    <greenlet.greenlet object at 0x005DF298>:{'stack': [1]}
    <greenlet.greenlet object at 0x0061F1E8>:{'stack': [2, 4]}
    协程gr1获取top: 1
    协程gr2释放:4
    协程gr2释放后:
    <greenlet.greenlet object at 0x005D4A28>:{'stack': [8, 18]}
    <greenlet.greenlet object at 0x005DF298>:{'stack': [1]}
    <greenlet.greenlet object at 0x0061F1E8>:{'stack': [2]}
    协程gr2获取top: 2
    协程m:
    <greenlet.greenlet object at 0x005D4A28>:{'stack': [8, 18]}
    <greenlet.greenlet object at 0x005DF298>:{'stack': [1]}
    <greenlet.greenlet object at 0x0061F1E8>:{'stack': [2]}
    

      

      

  • 相关阅读:
    使用NDK开发SQLite3
    SQL Server 2005 Default Trace (默认跟踪)
    MySQL 获得当前日期时间 函数
    利用UltraISO写入U盘安装系统,条件:电脑支持USBHDD ,U盘容量足够
    Sicily 1157 The hardest problem
    Histogram of oriented gradients(HOG)
    IE中的CSS3不完全兼容方案
    MySQL如何查询两个日期之间的记录
    查找某个字段最大值的记录 SQL 语句
    用 jQuery 实现页面滚动(Scroll)效果的完美方法
  • 原文地址:https://www.cnblogs.com/bad-robot/p/10079513.html
Copyright © 2020-2023  润新知