博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Flask的上下文管理:Werkzeug库的local模块
阅读量:4986 次
发布时间:2019-06-12

本文共 14538 字,大约阅读时间需要 48 分钟。

1、协程greenlet

from greenlet import greenletfrom greenlet import getcurrentdef 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_identfrom 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 = 8l.M = 8print("协程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:
8协程a:
1协程b:
2协程m:
8
:{'m': 8, 'M': 8}
:{'a': 1, 'A': 3}
:{'b': 2, 'B': 4}

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

  源码:

from greenlet import getcurrent as get_identfrom 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 = 8l.M = 8print("协程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:
8协程a:
1协程b:
2协程a:
||是否有l.a: False协程b:
||是否有l.b: False协程m:
8
:{'m': 8, 'M': 8}

 3、线程_thread

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

  • _thread
  • threading(推荐使用)

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

  源码:

import _threadfrom _thread import get_identfrom time import sleepdef 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_threadfrom 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 1l.__storage__: {12548: {'m': 8, 'M': 8}, 10656: {'a': 1, 'A': 3}}线程b:11564 2l.__storage__: {12548: {'m': 8, 'M': 8}, 10656: {'a': 1, 'A': 3}, 11564: {'b': 2, 'B': 4}}线程m:12548 8l.__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_threadfrom 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 2l.__storage__: {11480: {'m': 8, 'M': 8}, 12560: {'b': 2, 'B': 4}}释放后l.__storage__: {11480: {'m': 8, 'M': 8}}线程a:7628 1l.__storage__: {11480: {'m': 8, 'M': 8}, 7628: {'a': 1, 'A': 3}}释放后l.__storage__: {11480: {'m': 8, 'M': 8}}线程m:11480 8l.__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 greenletfrom werkzeug.local import LocalStackls = 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添加后:
:{'stack': [8, 18]}协程gr1添加后:
:{'stack': [8, 18]}
:{'stack': [1, 3]}gr2添加后:
:{'stack': [8, 18]}
:{'stack': [1, 3]}
:{'stack': [2, 4]}协程gr1释放:3协程gr1释放后:
:{'stack': [8, 18]}
:{'stack': [1]}
:{'stack': [2, 4]}协程gr1获取top: 1协程gr2释放:4协程gr2释放后:
:{'stack': [8, 18]}
:{'stack': [1]}
:{'stack': [2]}协程gr2获取top: 2协程m:
:{'stack': [8, 18]}
:{'stack': [1]}
:{'stack': [2]}

  

  

 

转载于:https://www.cnblogs.com/bad-robot/p/10079513.html

你可能感兴趣的文章
《ASP.NET SignalR系列》第五课 在MVC中使用SignalR
查看>>
我要回家-割舍不断的亲情
查看>>
Catenyms (POJ2337) 字典序最小欧拉路
查看>>
ZT : 优秀程序员的两大要素:懒 + 笨
查看>>
Centos6.5-dnsmasq安装
查看>>
PyCharm+Eclipse共用Anaconda的数据科学环境
查看>>
笔记3 | 通过onWindowAttributesChanged和onSystemUiVisibilityChange监听状态栏页面的隐藏与显示、动态显示与隐藏状态栏...
查看>>
msysgit 上传文件夹,规范化的日常
查看>>
CSS清除浮动
查看>>
Zookeeper之ZKClient的使用
查看>>
WTF小程序之animation
查看>>
那些前端二进制操作API
查看>>
一 、Spring Boot 学习之项目搭建
查看>>
一键部署joomla开源内容管理平台
查看>>
opencv画图
查看>>
Python-爬虫-12306购票业务实现
查看>>
010. windows10下安装kivy 1.9.1版
查看>>
AS3.0判断数组中最大值
查看>>
系统融合方案
查看>>
Hanoi塔问题(递归)
查看>>