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]}

  

  

 

posted @ 2018-12-06 21:03  RobotsRising  阅读(1004)  评论(0编辑  收藏  举报