tornaod十三:继续协程实现步异
上一章,AB两个请求,对A请求实现了异步。
对A请求实现了异步,但问题:不能将A请求视为一个简单的函数,而是需要做为生成器来使用。如果同时对B也实现异步,那么要不断的定义另一个不同名称的全局gen对象。
怎么将A请求作为普通函数,又要满足它是实现异步需要的生成器?
写个实现异步的生成器,作为装饰器,装饰在普通函数A请求中。同样,可以加在B请求上。
一、协程实现异步的装饰器:
将global gen; gen=reqA(); next(gen)提取出来,作为装饰器
def genCoroutine(func): def wrapper(*args, **kwargs): global gen gen = func(*args, **kwargs) next(gen) return wrapper
其它地方不变:
# _*_ coding: utf-8 _*_ import time import threading import genCoroutine gen = None def longIo(): def run(): print(u"开始耗时操作") time.sleep(10) print(u"结束耗时操作") try: global gen gen.send(u"longIo(handler)返回的数据") except StopIteration as e: pass threading.Thread(target=run).start() @genCoroutine def reqA(): print(u"开始处理reqA") res = yield longIo() print(u"接收到longIo(handler)的响应数据:%s" % res) print(u"开始结束reqA") def reqB(): print(u"开始处理reqB") time.sleep(2) print(u"开始结束reqB") def main(): reqA() reqB() while True: time.sleep(0.1) if __name__ == '__main__': main()
处理流程:同上一章协程实现异步的过程和结果一样
开始处理reqA
开始耗时操作
开始处理reqB
开始结束reqB
结束耗时操作
接收到longIo(handler)的响应数据:longIo(handler)返回的数据
开始结束reqA
问题:
1.处理掉全局变量gen;
之所以定义全局变量gen,是因为在longIo中要使用它gen.send(longIo返回的数据)。
解决办法:去掉longIo中要使用到的gen,封装到同一个地方:genCoroutine
2.处理掉耗时操作longIo中的线程
去掉longIo中的线程,也封装到genCoroutine装饰器中。
二、优化genCoroutine:将线程、全局生成器gen封装到genCoroutine中
def genCoroutine(func): def wrapper(*args, **kwargs): # 1.得到reqA的生成器:在reqA中定义yield longIo(); # 如果reqA中没有定义yield longIo,那么执行func(),得到的就不是生成器,而是函数返回值 gen1 = func(*args, **kwargs) # reqA的生成器 # 2.1执行生成器next(gen1):即执行longIo()。 # 如果我们没有在longIo中定义yield "返回的数据",那么得到的就是longIo()的返回值 # 如果我们在longIo中定义了yield "返回的数据",那么得到的就是longIo()的生成器 # 为了挂起longIo,并将线程从longIo中拆离,且要将生成器gen从longIo中拆离,封装到此 # 那么,我们需要的就不是longIo的返回值,而是longIo生成器。 gen2 = next(gen1) # longIO的生成器 # 2.2要得到longIo的生成器,需在longIo中也定义一个生成器:yield "返回的数据" # 那么执行longIo(),即next(gen1)时,即得到longIo的生成器gen2 def run(g): res = next(g) try: gen1.send(res) # 4.将longIo执行后的数据返回给reqA except StopIteration as e: pass # 3.1想要使耗时longIo(handler)操作异步返回,我们需要将它挂起;要将它挂起,我们需要为创建一个线程来执行它 threading.Thread(target=run, args=(gen2,)).start() return wrapper
# _*_ coding: utf-8 _*_ import time import threading def longIo(): print(u"开始耗时操作") time.sleep(10) print(u"结束耗时操作") # 返回数据 yield u"longIO(handler)返回的数据" @genCoroutine def reqA(): print(u"开始处理reqA") res = yield longIo() print(u"接收到longIo(handler)的响应数据:%s" % res) print(u"开始结束reqA") def reqB(): print(u"开始处理reqB") time.sleep(2) print(u"开始结束reqB") def main(): reqA() reqB() while True: time.sleep(0.1) if __name__ == '__main__': main()
处理流程:同上面一样
开始处理reqA 开始耗时操作 # .....挂起reqA的耗时操作 开始处理reqB 开始结束reqB # ....耗时操作......... 结束耗时操作 接收到longIo(handler)的响应数据:longIO(handler)返回的数据 开始结束reqA
回调函数实现的异步,在回调函数中(longIo)返回数据(不能使用return);协程实现的异步,在gen2生成器(longIo)中调用生成器.send方法发送数据。
posted on 2018-08-11 15:31 myworldworld 阅读(146) 评论(0) 收藏 举报