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