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