返回介绍

16.10 本章小结

发布于 2024-02-05 21:59:47 字数 1878 浏览 0 评论 0 收藏 0

Guido van Rossum 写道,生成器有三种不同的代码编写风格:

有传统的“拉取式”(迭代器)、“推送式”(例如计算平均值那个示例),还有“任务式”(读过 Dave Beazley 写的协程教程了吗……)。17

17摘自对 Python-ideas 邮件列表中“Yield-From: Finalization guarantees”消息的回复。Guido 所说的 David Beazley 写的教程是“A Curious Course on Coroutines and Concurrency”。

第 14 章专门介绍了迭代器,本章则介绍了“推送式”协程,还介绍了特别简单的“任务式”——仿真示例中的出租车进程。第 18 章会在并发编程中使用这两种技术实现异步任务。

计算移动平均值的示例展示了协程的常见用途:累加器,处理接收到的值。我们知道,可以在协程上应用装饰器,预激协程;在某些情况下,这么做更方便。不过要记住,预激装饰器与协程的某些用法不兼容。尤其是 yield from subgenerator(),这个结构假定 subgenerator 没有预激,然后自动预激。

每次调用 send 方法时,作为累加器使用的协程可以获取部分结果,不过能返回值的协程更有用。这个特性在 PEP 380 中定义,于 Python 3.3 引入。我们知道,现在生成器中的 return the_result 语句会抛出 StopIteration(the_result) 异常,这样调用方可以从异常的 value 属性中获取 the_result。这样获取协程的结果还是很麻烦,不过 PEP 380 引入的 yield from 句法能自动处理。

探讨 yield from 结构时,我们首先从使用简单的迭代器的示例入手,然后又举了一个例子,重点说明 yield from 结构的三个主要组件:委派生成器(在定义体中使用 yield from),yield from 激活的子生成器,以及通过委派生成器中 yield from 表达式架设起来的通道把值发给子生成器,从而驱动整个过程的客户代码。最后,那一节参照 PEP 380 中使用的英语和类似 Python 的伪代码分析了 yield from 结构的正式定义。

本章最后举了一个离散事件仿真示例,说明如何使用生成器代替线程和回调,实现并发。那个出租车仿真系统虽然简单,但是首次一窥了事件驱动型框架(如 Tornado 和 asyncio)的运作方式:在单个线程中使用一个主循环驱动协程执行并发活动。使用协程做面向事件编程时,协程会不断把控制权让步给主循环,激活并向前运行其他协程,从而执行各个并发活动。这是一种协作式多任务:协程显式自主地把控制权让步给中央调度程序。而多线程实现的是抢占式多任务。调度程序可以在任何时刻暂停线程(即使在执行一个语句的过程中),把控制权让给其他线程。

最后要说明一点,本章对协程的定义是宽泛的、不正式的,即:通过客户调用 .send(...) 方法发送数据或使用 yield from 结构驱动的生成器函数。写作本书时,“PEP 342— Coroutines via Enhanced Generators”和现有的大多数 Python 书籍都使用这个宽泛的定义。第 18 章介绍的 asyncio 库建构在协程之上,不过采用的协程定义更为严格:在 asyncio 库中,协程(通常)使用 @asyncio.coroutine 装饰器装饰,而且始终使用 yield from 结构驱动,而不通过直接在协程上调用 .send(...) 方法驱动。当然,在 asyncio 库的底层,协程使用 next(...) 函数和 .send(...) 方法驱动,不过在用户代码中只使用 yield from 结构驱动协程运行。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文