我们知道生成器有两种形式:
1.(x for _ in range(10))也就是列表生成式改成( )而不是[ ]
2.用了yield的函数
协程是什么:协程又称微线程,纤程,python中协程是通过生成器来支持的
子程序或者称为函数,子程序的互相调用会形成调用栈,需要一层层返回,子程序是默认return None的,也就是返回了函数就结束了,下次执行又是从头开始------>子程序是协程的一种特例
协程有什么好处:协程可以实现用一个线程来进行异步IO,也就是说不像函数那样,一个线程执行一个函数,当一个线程因为IO阻塞时,需要进行切换线程才能实现异步的效果
我们传统的生产者-消费者模型是通过多线程来实现的,一个线程写,一个线程读,通过线程获得锁防止数据的不一致性
但是如果用协程来实现,同一个线程内,一个函数写完,yield出来给另一个函数读,读完在通过send()再次进入写函数进行上次的后续执行
例子:
def Gene(): #生成器函数
print("ok")
x = 100
print(x)
first = yield 50 #这里就是send函数的关键
# send所传递的值其实就是给 =号左边的左值赋值
print(first)
second = yield x # 这里试第二个断点
print(second)
z = 'third'
third = yield z
print(third)
inst = Gene() #创建生成器对象,并没有启动,也就是没有执行进去
output1 = inst.send(None) #启动生成器,运行到第一个yield
print(output1) #这边的output1获得的是yield的返回值 50
output2 = inst.send(30)
print(output2)
output3 = inst.send(None)
#执行结果:
# ok
# 100
# 50
# 30
# 100
# None
这个代码关键是要看懂xx=yield xx,和send(xx)
我们需要知道:一开始inst.send(None)是用来启动生成器的,也就是执行进去,然后print("ok"),print(x),然后执行到yield 50把50给抛出来赋值给了output1,然后print(output1),然后又通过inst.send(30)进入到生成器上次执行的后续,yield 50已经执行过了,接下来就是send(30)赋值给first,然后print(first),然后yeild x也就是抛出了100,给output2接收,print(output2),在send(None)再次进入上次执行的后续,也就是second被赋值None,然后print(second),一直执行到yield z也就是抛出‘third’,然后就没有后续了。即便我们没有关闭生成器---->inst.close()
可以看出这里面已经又涉及到类似函数调用了,只需要通过send()就可以返回到上次执行的后续
我们可以看出,xx=yield yy是先抛出yy,再把其他地方send的东西赋值给xx
注意:这里的最开始的send(None)仅用于启动生成器,当然我们也可以用next(Gene)来启动生成器
下面我们来写一下生产者-消费者的协程实现:
# 消费者
def consumer():
response = None
while True:
item = yield response
if not item:
return None
print('consumer is consume {0}'.format(item))
response = 'consume done'
# 生产者
def producer(con):
con.send(None)
n = 0
for i in range(1, 13):
n += 1
print('producer have prodeced {0}'.format(i))
result = con.send(n)
print('consumer return {0}'.format(result))
con.close()# 关闭生成器
con = consumer()
producer(con)