Flask的上下文管理:Werkzeug庫的local模塊

一、協程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″不會被執行。python

  getcurrent()用來獲取協程的id。app

二、使用greenlet實現爲每一個協程開闢數據存儲空間

2.一、爲每一個協程開闢數據存儲空間

  源碼:ide

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.二、在協程執行完後釋放數據存儲空間

  源碼:線程

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}

 三、線程_thread

  Python3 線程中經常使用的兩個模塊爲:對象

  • _thread
  • threading(推薦使用)

  thread 模塊已被廢棄。用戶可使用 threading 模塊代替。因此,在 Python3 中不能再使用"thread" 模塊。爲了兼容性,Python3 將 thread 重命名爲 "_thread"。blog

  源碼:get

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

四、使用_thread實現爲每一個線程開闢數據存儲空間

4.一、爲每一個線程開闢數據存儲空間

  源碼:

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.二、在線程執行完後釋放數據存儲空間

  源碼:

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

五、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.一、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]}
相關文章
相關標籤/搜索