我们可以认为一个线程是调用某个函数方法,协程可以控制函数方法的执行过程,转向其他函数方法,并在适当的时候切换到原来的函数方法中继续执行。python中常见的协程模块有yield、yield from、async/wait、asyncio、Gevent等。只有Gevent是第三方模块,其他都是python的内置模块
1. yield
def consumer():
"""
任务1:接收数据,处理数据
:return:
"""
print('开始接受数据')
while True:
print('等待中')
x = yield
print('处理数据:', x)
def producer():
"""
任务2:生产数据
:return:
"""
c = consumer()
# 找到consumer()的yield位置
next(c)
for i in range(2):
print('发送数据:', i)
c.send(i)
if __name__ == '__main__':
producer()
result:
开始接受数据
等待中
发送数据: 0
处理数据: 0
等待中
发送数据: 1
处理数据: 1
等待中
分析过程如下:
(1)当我们调用producer方法的时候,方法中调用了consumer方法,并生成了方法对象c
(2)consumer方法处于死循环状态。如果按照正常的调用方式,它会使producer方法处于死循环。但通过使用yield可以将consumer方法和producer方法相互切换
(3)当consumer方法的对象c调用send方法的时候,程序从producer方法切换到consumer方法的yield位置开始执行consumer方法
(4)由于consumer方法处于死循环状态,当再次执行到yield位置的时候,代表consumer方法已执行完成,程序会自动切换到producer方法继续执行
2. yield from
从3.3版本开始,引入了yield from语句。它不仅简化了yield多层嵌套的代码,还弥补了yield的不足。其语法如下:
# iterable为可迭代对象,如列表、元组、生成器等
yield from iterable为可迭代对象,如列表、元组、生成器等
该语法等同于下面的代码:
for item in iterable:
yield item
yield from重要的作用是提供了一个数据传输管道
def consumer():
"""
任务1:接收数据,处理数据
:return:
"""
print('开始接受数据')
while True:
print('等待中')
x = yield
print('处理数据:', x)
def wraps(c):
while True:
print('running')
yield from c
def producer(wrap):
"""
任务2:生产数据
:return:
"""
next(wrap)
for i in range(2):
print('发送数据:', i)
wrap.send(i)
if __name__ == '__main__':
c = consumer()
wrap = wraps(c)
producer(wrap)
result:
running
开始接受数据
等待中
发送数据: 0
处理数据: 0
等待中
发送数据: 1
处理数据: 1
等待中
producer方法和consumer方法之间开始是通过wraps方法传递函数对象的,但是wraps方法只是为producer方法和consumer方法提供一个数据传输管道,不参与producer方法和consumer方法之间的数据通信。