Coroutine 练习 1 - Coroutine Exercises 1

 字典中为动词 “to yield” 给出了两个释义:产出和让步。对于 Python 生成器中的 yield 来
说,这两个含义都成立。 yield item 这行代码会产出一个值,提供给 next(...) 的调
用方;此外,还会作出让步,暂停执行生成器,让调用方继续工作,直到需要使用另一个
值时再调用 next()。调用方会从生成器中拉取值。
从句法上看,协程与生成器类似,都是定义体中包含 yield 关键字的函数。可是,在协
程中, yield 通常出现在表达式的右边(例如, datum = yield),可以产出值,也可
以不产出,如果 yield 关键字后面没有表达式,那么生成器产出 None。协程可能会从
调用方接收数据,不过调用方把数据提供给协程使用的是 .send(datum) 方法,而不是
next(...) 函数。通常,调用方会把值推送给协程。
yield 关键字甚至还可以不接收或传出数据。不管数据如何流动, yield 都是一种流程控
制工具,使用它可以实现协作式多任务:协程可以把控制器让步给中心调度程序,从而激
活其他的协程。从根本上把 yield 视作控制流程的方式,这样就好理解协程了。 生成器如何进化成协程
协程的底层架构在 “PEP 342—Coroutines via Enhanced Generators”
(https://www.python.org/dev/peps/pep-0342/)中定义,并在 Python 2.5(2006
年)实现了。自此之后, yield 关键字可以在表达式中使用,而且生成器 API 中增加了
.send(value) 方法。生成器的调用方可以使用 .send(...) 方法发送数据,发送的数据
会成为生成器函数中 yield 表达式的值。因此,生成器可以作为协程使用。协程是指一
个过程,这个过程与调用方协作,产出由调用方'提供'的值。
除了 .send(...) 方法, PEP 342 还添加了 .throw(...) 和 .close() 方法:前者的作
用是让调用方抛出异常,在生成器中处理;后者的作用是终止生成器。 协程最近的演进来自 Python 3.3(2012 年)实现的
“PEP 380—Syntax for Delegating to a Subgenerator”
(https://www.python.org/dev/peps/pep-0380/)。
PEP 380 对生成器函数的句法做了两处改动,以便更好地作为协程使用。
现在,生成器可以返回一个值;以前,如果在生成器中给 return 语句提供值,会抛
出 SyntaxError 异常。新引入了 yield from 句法,使用它可以把复杂的生成器重构成小型的嵌套生成器,
省去了之前把生成器的工作委托给子生成器所需的大量样板代码。 例子,
def coroutine_example():
print ('coroutine started')
x = yield # 协程使用生成器函数定义:定义体中有 yield 关键字。
# yield 在表达式中使用;如果协程只需从客户那里接收数据,那么产出的值是 None,
# 这个值是隐式指定的,因为 yield 关键字右边没有表达式
print ('coroutine received:', x) Output,
>>> coro = coroutine_example()
>>> print (coro) # 与创建生成器的方式一样,调用函数得到生成器对象
<generator object coroutine_example at 0x034458D0>
>>> next(coro) # 首先要调用 next(...) 函数,因为生成器还没启动,没在 yield 语句处暂停,所以一开始无法发送数据
coroutine started # 携程已激活, 等待数据过来
# 这一步通常称为“预激”(prime)协程(即,让协程向前执行到第一个 yield 表达式,准备好作为活跃的协程使用)
>>>coro.send('haha') # 调用 send 方法后,协程定义体中的 yield 表达式会计算出 haha;
# 现在,协程会恢复,一直运行到下一个 yield 表达式,或者终止。
coroutine received: haha
StopIteration # 这里,控制权流动到协程定义体的末尾,导致生成器像往常一样抛出 StopIteration 异常。 协程可以身处四个状态中的一个。
当前状态可以使用 inspect.getgeneratorstate(...) 函数确定,该函数会返回下述字符串中的一个。
'GEN_CREATED'
   等待开始执行。
'GEN_RUNNING'
   解释器正在执行。
只有在多线程应用中才能看到这个状态。此外,生成器对象在自己身上调用 getgeneratorstate 函数也行,不过这样做没什么用。
'GEN_SUSPENDED'
  在 yield 表达式处暂停。
'GEN_CLOSED'
  执行结束。 因为 send 方法的参数会成为暂停的 yield 表达式的值,所以,仅当协程处于暂停状态时
才能调用 send 方法。不过,如果协程还没激活(即,状态是 'GEN_CREATED'),情况就不同了。
因此,始终要调用 next(my_coro) 激活协程——也可以调用 my_coro.send(None),效果一样。 例子,
def coroutine_example2(a):
print ('coroutine start a = ',a) #
b = yield a
print ('received b = ', b) #
c = yield a + b
print ('received c = ', c) coro2= coroutine_example2(5)
print (next(coro2)) #
#coro2.send(None) # 调用 next(my_coro) 或 my_coro.send(None) 激活协程,效果一样.
print (coro2.send(7)) #
coro2.send(10) Output,
coroutine start a = 5 # 向前执行协程到第一个 yield 表达式,打印 -> coroutine start a = 5(#1) 消息,
# 然后产出 a 的值,并且暂停,等待为 b 赋值.
5 #
received b = 7 # 把 7 发给暂停的协程;计算 yield 表达式,得到 7,然后把那个数绑定给 b。
# 打印 -> Received: b = 7 (#2)消息,-> 程序继续,接着产出 a + b 的值(12),
# 然后协程暂停,等待为 c赋值。
12 # received c = 10 # 把数字 10 发给暂停的协程;计算 yield 表达式,得到 10,然后把那个数绑定给 c,
# 进而, 打印 -> Received: c = 10 消息,然后协程终止,导致生成器对象抛出StopIteration 异常。
StopIteration

Coroutine 练习 1 - Coroutine Exercises 1的更多相关文章

  1. ngx_lua_API 指令详解(五)coroutine.create,coroutine.resume,coroutine.yield 等集合指令介绍

    ngx_lua 模块(原理实现) 1.每个worker(工作进程)创建一个Lua VM,worker内所有协程共享VM: 2.将Nginx I/O原语封装后注入 Lua VM,允许Lua代码直接访问: ...

  2. The Coroutine

    关于Coroutine 说到coroutine就不的不说subroutine,也就是我们常用到的一般函数.调用一个函数开始执行,然后函数执行完成后就退出,再次调用的时候,再从头开始,调用之间是没有保存 ...

  3. python中的generator(coroutine)浅析和应用

    背景知识: 在Python中一个function要运行起来,它在python VM中需要三个东西. PyCodeObject,这个保存了函数的代码 PyFunctionObject,这个代表一个虚拟机 ...

  4. Lua Coroutine详解

    协同程序与线程差不多,也就是一条执行序列,拥有自己独立的栈,局部变量和指令指针,同时又与其它协同程序共享全局变量和其它大部分东西.线程与协同程序的主要区别在于,一个具有多线程的程序可以同时运行几个线程 ...

  5. 【Unity3D基础教程】给初学者看的Unity教程(五):详解Unity3D中的协程(Coroutine)

    作者:王选易,出处:http://www.cnblogs.com/neverdie/ 欢迎转载,也请保留这段声明.如果你喜欢这篇文章,请点[推荐].谢谢! 为什么需要协程 在游戏中有许多过程(Proc ...

  6. Lua 协程coroutine

    协程和一般多线程的区别是,一般多线程由系统决定该哪个线程执行,是抢占式的,而协程是由每个线程自己决定自己什么时候不执行,并把执行权主动交给下一个线程. 协程是用户空间线程,操作系统其存在一无所知,所以 ...

  7. U3D的飞船太空射击例子中,使用coroutine

    coroutine 协同程序与线程差不多,也就是一条执行序列,拥有自己独立的栈,局部变量和指令指针,同时又与其它协同程序共享全局变量和其它大部分东西.线程与协同程序的主要区别在于,一个具有多线程的程序 ...

  8. 【转】Lua coroutine 不一样的多线程编程思路

    Lua coroutine 不一样的多线程编程思路 Sunday, Apr 26th, 2009 by Tim | Tags: coroutine, Lua 上周末开始看<Lua程序设计> ...

  9. Lua中的协同程序 coroutine

    Lua中的协程和多线程很相似,每一个协程有自己的堆栈,自己的局部变量,可以通过yield-resume实现在协程间的切换.不同之处是:Lua协程是非抢占式的多线程,必须手动在不同的协程间切换,且同一时 ...

随机推荐

  1. ArcEngine 数据编辑(IWorkspaceFactory)

    数据编辑做过很多次,没怎么出现问题,今天出现了问题,浪费了大半天,记录一下. 问题:修改Featrue的属性,修改后停止编辑,但是没有提示是否保存修改 原因:在编辑数据的时候没有加StartEditO ...

  2. 原生js实现音乐列表(隔行换色、全选)

    一.实现原理: 1.使用 % 运算符实现各行换色,规律:当%前面的值和后面的值相同时  结果为0: 2.使用开关思想,实现在同一个元素上反复点击时的条件判断,并且把开关以属性方式绑定在每个元素上: 3 ...

  3. Spirng Boot2 系列教程(二十二)| 启动原理

    一个读者,也是我的好朋友投稿的一篇关于 SpringBoot 启动原理的文章,才大二就如此优秀,未来可期. 我一直想了解一下 SpirngBoot 的是如何启动的,我想就来写一篇关于 SpirngBo ...

  4. AVR单片机教程——串口接收

    本文隶属于AVR单片机教程系列.   上一讲中,我们实现了单片机开发板向电脑传输数据.在这一讲中,我们将通过电脑向单片机发送指令,让单片机根据指令控制LED.这一次,两端的TX与RX需要交叉连接,单片 ...

  5. flash-session

    作用:更改session存储的位置 1.session默认存放在浏览器的cookie中 源码 wsgi->app.__call__->wsgi_app->push->self. ...

  6. 【5min+】帮我排个队,谢谢。await Task.Yield()

    系列介绍 [五分钟的dotnet]是一个利用您的碎片化时间来学习和丰富.net知识的博文系列.它所包含了.net体系中可能会涉及到的方方面面,比如C#的小细节,AspnetCore,微服务中的.net ...

  7. .net core 3.1 DbFirst mysql

    这是一套完全配置正确的方式 创建项目此步骤省略 打开nuget 搜索 Pomelo.EntityFrameworkCore.MySql 添加完毕该引用之后nuget 搜索 Microsoft.Enti ...

  8. xhemj资料

    Github https://github.com/xhemj Gitee码云 https://gitee.io/xhemj Cnblogs博客园 https://www.cnblogs.com/xh ...

  9. Docker安装之路

    从3月初到现在,一直在安装docker 的路上越走越远,大概就在1个小时前,我终于成功了,那一刻,我觉得我拥有了整个世界,于是乎,拥有了整个世界的我决定草率的并粗略的记录一下安装过程中遇到的我能记住的 ...

  10. 团队第一次作业(By七个小矮人)

    一.团队简介 1.团队名称:七个小矮人 2.团队成员列表 201731024137 马驰(队长) 201731021227 于丁 201731024114 杨汶桐 201731024125 李朋珂 2 ...