从语法上来看,协程和生成器类似,都是在定义体中包含yield关键字的函数
但在协程中
yield关键字通常出现在表达式的右边:
- 可以产出值n(y = yield n)
- 也可以不产出值(y = yield),或者说是产出值为None
通过next(coroutine)函数激活协程:
- 调用next(),返回yield右边的可有可无的值或者函数值(一般不需要next产出值,即,yield后无值,= yield),暂停
调用方是通过send(datum=None)的方式把数据提供给协程使用:
- send(n)函数的返回值为yield右边的值或者函数值
- 等号左边的变量接受send(n)函数传来的值
- 可以理解为函数next()和函数send(n)都会执行yield右边的值或者函数值,
- 但是,send(n)函数执行完不会暂停,同时send(n)函数的参数n会赋值给等号左边的变量
def
![25574031440e643018ca572fa77d6031.png](https://i-blog.csdnimg.cn/blog_migrate/ded0e12dc1f0cd126ab26ce4d05577e3.jpeg)
这里的对应于send(n)的操作 y = yield 实际上是按2步进行的
- 第1步yield接受send(n)函数传来的参数值,并赋值给等号=左边的变量,即y=n
- 第2步执行yield后面的表达式或者函数并返回值
为了查看协程在运行过程中的四个状态,我们引入from inspect import getgeneratorstate
- GEN_CREATED:生成器创建完成,等待执行,可以理解为线程的就绪状态
- GEN_RUNNING:一般看不到,可理解为线程的执行状态
- GEN_SUSPENDED:在yield表达式处暂停,可理解为线程的阻塞状态
- GEN_CLOSED:执行结束,可理解为线程的死亡状态
![a5857820bd0b11d206b4b0dd690aa6a9.png](https://i-blog.csdnimg.cn/blog_migrate/703ec0da823479b9a390c48520b00efc.jpeg)
获取协程的返回值
- 从异常属性中获取:协程结束时会跟生成器一样抛出StopIteration的异常,返回值就在异常对象的value属性中
- yield from内部会自动捕获后面协程StopIteration异常,并把异常对象的value属性变成yield from的返回值
- yield from 的主要功能就是打开双向通道,最外层的调用方调用子生成器,同时子生成器也可使用yield from调用另一个子生成器,一直嵌套调用直到遇到yield表达式结束
- send(n)发送的值n通过yield from直接传递给了最内层的子生成器,并在yield from处等待子生成器的返回
![0ccd22c73719fd3f5d83e47c581833d9.png](https://i-blog.csdnimg.cn/blog_migrate/9a0c86aace8057669583d9e4a0cd7c26.jpeg)
![83704d7ff350551764357cf8ff818849.png](https://i-blog.csdnimg.cn/blog_migrate/678ecee70b5dccad19d6a4d1c5087b04.jpeg)
异步IO(asyncio)
- Python 3.4版本引入异步IO的标准库asyncio,使用事件循环驱动协程实现并发。
- 在asyncio库中,用asyncio.coroutine装饰,用yield from来驱动协程
- Python 3.5版本中 用async代替了asyncio.coroutine,用await代替了yield from
下面展示了Python 3.4中标准库asyncio中协程(coroutine)的应用
import threading import asyncioasynciowww.liaoxuefeng.com
@asyncio.coroutine def hello():
print('Hello world! (%s)' % threading.currentThread()) yield from asyncio.sleep(1)
print('Hello again! (%s)' % threading.currentThread())
loop = asyncio.get_event_loop()
tasks = [hello(), hello()]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
![2de0520b6675539e3875a7cb3a4af94a.png](https://i-blog.csdnimg.cn/blog_migrate/8ea5bfe3533a68ebb44ab03f0a569c6e.jpeg)