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)    收藏  举报

导航