Python 高级编程和异步IO并发编程 --12_9 生成器实现协程

# 生成器是可以暂停的函数
import inspect
def gen_func():
    yield 1   # 返回值给调用方;调用方通过send方式返回值给gen
    return "Tom"

if __name__=="__main__":
    gen = gen_func()
    print(inspect.getgeneratorstate(gen))
    next(gen)
    print(inspect.getgeneratorstate(gen))
    try:
        next(gen)
    except StopIteration as e:
        pass
    print(inspect.getgeneratorstate(gen))
GEN_CREATED
GEN_SUSPENDED
GEN_CLOSED

原先只知道yield可以返回一个值,使函数变为生成器,然后用for迭代或是用next()方法不断调用生成值,今天才知道生成器也可以接收值,用他的send()方法。
先看以下示例:

def customer():
    r = '这是初始化结果'
    while True:
        n = yield r
        print('-----------------')
        r = r+str(n)

g = customer()     #g为生成器对象
print(g.send(None))    #必须先发送None来初始化生成器,代码第一次运行到yield处,返回初始化的r值,n的值没有返回,他就是等待传入的值
print('**********')
print(g.send('aaaa')) # 这时传入了参数了,并将传入的数据返回给了n,生成器从yield'位置再次启动,执行到yield停下来,并返回处理过的r
print('**********')
print(g.send('bbbb'))#同上
print('**********')
print(g.__next__())#直接调用next相当于 g.send(None'),n接受的值为None
print(next(g))
这是初始化结果
**********
-----------------
这是初始化结果aaaa
**********
-----------------
这是初始化结果aaaabbbb
**********
-----------------
这是初始化结果aaaabbbbNone
-----------------
这是初始化结果aaaabbbbNoneNone

从上面代码可以统一next()和send(),next()是send(None).而生成器的启动必须要传入一个None,所以用next()或者send(None)都可以启动一个生成器。通过send,或者next方法就可以进入到函数体内执行函数内的方法,执行完后又会返回到原来的执行位置,这就形成了主执行代码块和函数内代码块不断交换执行过程,这就叫协程。

接下来用协程完成一个生产者消费者的模型

def customer():
    r = ''
    while True:
        n = yield r

        print('接受到商品%s,正在处理商品..'%n)
        r = 'ok'
        print('处理完毕正在返回消息给生产者')

def producer(g):
    '''
    :param g:消费者生成器
    :return:
    '''
    g.send(None)
    for i in range(3):
        print('生产了商品%s'%i)
        b = g.send(i)
        print('消费者回馈的消息是%s'%b)


g =customer()
producer(g)
生产了商品0
接受到商品0,正在处理商品..
处理完毕正在返回消息给生产者
消费者回馈的消息是ok
生产了商品1
接受到商品1,正在处理商品..
处理完毕正在返回消息给生产者
消费者回馈的消息是ok
生产了商品2
接受到商品2,正在处理商品..
处理完毕正在返回消息给生产者
消费者回馈的消息是ok

这样就实现了,生产者生产一个东西,消费者就接受处理,并返回消息,返回消息后生产者继续生产下一个商品。

总结:通过yield生成器可以完成函数执行的有序切换,形成了两函数间的协同配合,叫做协程。
协程相比线程他没有额外的切换线程的开销,且无需上锁,因为它的任务调度完全取决于你写的代码,不存在这个任务执行一般时其他任务开始造成的混乱。
我的理解:实质上协程就是不同功能的函数间的切换执行,她其实是同步的执行,但由于不同函数的功能不同,加上切换的平率非常高,看上去就像是同时在执行两个不同的任务,这样就完成了多任务。

发布了380 篇原创文章 · 获赞 129 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/f2157120/article/details/105234500