python 用作协程的生成器的基本行为

先看如下示例:最简单的协程案例:
在这里插入图片描述
1、协程使用生成器函数定义:定义体中有 yield 关键字。
2、yield 在表达式中使用;如果协程只需从客户那里接收数据,那么产出的值是 None—— 这个值是隐式指定的,因为 yield 关键字右边没有表达式。
3、与创建生成器的方式一样,调用函数得到生成器对象。
4、首先要调用 next(...) 函数,因为生成器还没启动,没在 yield 语句处暂停,所以一开 始无法发送数据。
5、调用这个方法后,协程定义体中的 yield 表达式会计算出 100;现在,协程会恢复,一 直运行到下一个 yield 表达式,或者终止
6、这里,控制权流动到协程定义体的末尾,导致生成器像往常一样抛出 StopIteration 异常。

协程可以身处四个状态中的一个。当前状态可以使用 inspect.getgeneratorstate(...) 函 数确定,该函数会返回下述字符串中的一个。

'GEN_CREATED'   # 等待开始执行。

'GEN_RUNNING'  # 解释器正在执行。

'GEN_SUSPENDED'  # 在 yield 表达式处暂停。

'GEN_CLOSED'  # 执行结束。


因为 send 方法的参数会成为暂停的 yield 表达式的值,所以,仅当协程处于暂停状态时才 能调用 send 方法,例如 my_coro.send(100)。不过,如果协程还没激活(即,状态是 ‘GEN_ CREATED’),情况就不同了。因此,始终要调用 next(my_coro) 激活协程——也可以调用 my_coro.send(None),效果一样。

如果创建协程对象后立即None 之外的值发给它,会出现下述错误
在这里插入图片描述
注意错误消息,它表述得相当清楚。

最先调用 next(my_coro) 函数这一步通常称为“预激(prime)协程(即,让协程向前执 行到第一个 yield 表达式,准备好作为活跃的协程使用)。
在这里插入图片描述
1、inspect.getgeneratorstate 函数指明,处于 GEN_CREATED 状态(即协程未启动)。
2、向前执行协程到第一个 yield 表达式,打印 -> Started: a = 14 消息,然后产出 a 的 值,并且暂停,等待为 b 赋值。
3、getgeneratorstate 函数指明,处于 GEN_SUSPENDED 状态(即协程在 yield 表达式处暂停)。
4、把数字 28 发给暂停的协程;计算 yield 表达式,得到 28,然后把那个数绑定给 b。打 印 -> Received: b = 28 消息,产出 a + b 的值(42),然后协程暂停,等待为 c 赋值。
5、把数字 99 发给暂停的协程;计算 yield 表达式,得到 99,然后把那个数绑定给 c。打印 -> Received: c = 99 消息,然后协程终止,导致生成器对象抛出 StopIteration 异常。
6、 getgeneratorstate 函数指明,处于 GEN_CLOSED 状态(即协程执行结束)。

关键的一点是,协程在 yield 关键字所在的位置暂停执行。前面说过,在赋值语句中,= 右边的代码在赋值之前执行。因此,对于 b = yield a 这行代码来说,等到客户端代码再 激活协程时才会设定 b 的值。这种行为要花点时间才能习惯,不过一定要理解,这样才能 弄懂异步编程中 yield 的作用。

simple_coro2 协程的执行过程分为 3 个阶段,如下:
(1) 调用 next(my_coro2),打印第一个消息,然后执行 yield a,产出数字 14。
(2) 调用 my_coro2.send(28),把 28 赋值给 b,打印第二个消息,然后执行 yield a+ b,产 出数字 42。
(3) 调用 my_coro2.send(99),把 99 赋值给 c,打印第三个消息,协程终止。

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值