python 协程的学习记录
协程是个子程序,执行过程中,内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行
从句法上看,协程与生成器类似,都是定义体中包含 yield 关键字的函数。可是,在协
程中,yield 通常出现在表达式的右边(例如,datum = yield),可以产出值,也可
以不产出——如果 yield 关键字后面没有表达式,那么生成器产出 None。协程可能会从
调用方接收数据,不过调用方把数据提供给协程使用的是 .send(datum) 方法,而不是
next(...) 函数。通常,调用方会把值推送给协程。
yield 关键字甚至还可以不接收或传出数据。不管数据如何流动,yield 都是一种流程控
制工具,使用它可以实现协作式多任务:协程可以把控制器让步给中心调度程序,从而激
活其他的协程。
从根本上把 yield 视作控制流程的方式,这样就好理解协程了。
使用协程要注意的地方是
协程可以身处四个状态中的一个。当前状态可以使用
inspect.getgeneratorstate(...) 函数确定,该函数会返回下述字符串中的一个。
'GEN_CREATED'
等待开始执行。
'GEN_RUNNING'
解释器正在执行。
'GEN_SUSPENDED'
在 yield 表达式处暂停。
'GEN_CLOSED'
执行结束。
协程创建之后,需要激活,需要调用next函数来激活协程。
为了避免忘记,我们可以在协程上使用一个特殊的装饰器来帮助激活协程
from functools import wraps def coroutine(func):
@wraps(func)
def primer(*args, **kwargs):
gen = func(*args, **kwargs)
next(gen)
return gen
return primer
协程中未处理的异常会向上冒泡,传给 next 函数或 send 方法的调用方(即触发协程的
对象)
终止协程的一种方式:发送某个哨符值,让协程退出。内置的 None 和
Ellipsis 等常量经常用作哨符值。Ellipsis 的优点是,数据流中不太常有这个值。我
还见过有人把 StopIteration 类(类本身,而不是实例,也不抛出)作为哨符值;也就
是说,是像这样使用的:my_coro.send(StopIteration)。
从 Python 2.5 开始,客户代码可以在生成器对象上调用两个方法,显式地把异常发给协
程。
这两个方法是 throw 和 close。
generator.throw(exc_type[, exc_value[, traceback]])
致使生成器在暂停的 yield 表达式处抛出指定的异常。如果生成器处理了抛出的异
常,代码会向前执行到下一个 yield 表达式,而产出的值会成为调用 generator.throw
方法得到的返回值。如果生成器没有处理抛出的异常,异常会向上冒泡,传到调用方的上
下文中。
generator.close()
致使生成器在暂停的 yield 表达式处抛出 GeneratorExit 异常。如果生成器没有处
理这个异常,或者抛出了 StopIteration 异常(通常是指运行到结尾),调用方不会报
错。如果收到 GeneratorExit 异常,生成器一定不能产出值,否则解释器会抛出
RuntimeError 异常。生成器抛出的其他异常会向上冒泡,传给调用方。
协程在遇到异常或者哨符值是会退出。
协程在耗尽时会抛出StopIteration异常
对 yield from 结构来说,解释器不仅会捕获 StopIteration 异常,还会把
value 属性的值变成 yield from 表达式的值。
yield from 的主要功能是打开双向通道,把最外层的调用方与最内层的子生成器连接起
来,这样二者可以直接发送和产出值,还可以直接传入异常,而不用在位于中间的协程中
添加大量处理异常的样板代码。有了这个结构,协程可以通过以前不可能的方式委托职
责。
委派生成器
包含 yield from <iterable> 表达式的生成器函数。
子生成器
从 yield from 表达式中 <iterable> 部分获取的生成器。
调用方
PEP 380 使用“调用方”这个术语指代调用委派生成器的客户端代码。在不同的语境
中,我会使用“客户端”代替“调用方”,以此与委派生成器(也是调用方,因为它调用了子
生成器)区分开。

最后给个实例
from collections import namedtuple
Result = namedtuple('Result', 'count average')
def averager():
total = 0.0
count = 0
average = None
while True:
#此处接受send发送的值,发送None则退出协程,协程处于上下文管理器中,所以数据会叠加,只有第一次激活协程的使用才会初始化total=0,count=0,average=None
term = yield
if term is None:
break
total += term
count += 1
average = total / count
return Result(count, average)
def grouper(results, key):
while True:
results[key] = yield from averager()
def main(data):
results = {}
for key, values in data.items():
group = grouper(results, key)
next(group)
for value in values:
group.send(value)
group.send(None)
# print(results)
report(results)
def report(results):
for key, result in sorted(results.items()):
group, unit = key.split(';')
print('{:2} {:5} averaging {:.2f}{}'.format(result.count, group, result.average, unit))
data = {
'girls;kg':
[40.9, 38.5, 44.3, 42.2, 45.2, 41.7, 44.5, 38.0, 40.6, 44.5],
'girls;m':
[1.6, 1.51, 1.4, 1.3, 1.41, 1.39, 1.33, 1.46, 1.45, 1.43],
'boys;kg':
[39.0, 40.8, 43.2, 40.8, 43.1, 38.6, 41.4, 40.6, 36.3],
'boys;m':
[1.38, 1.5, 1.32, 1.25, 1.37, 1.48, 1.25, 1.49, 1.46],
}
if __name__ == '__main__':
main(data)
总结一下,使用协程的时,记得要激活协程,并且在协程耗尽时捕获异常,当然可以使用yield from来自动捕获,将协程看成是流程控制可能会好理解的多。
大部分内容摘自流畅的python第十六章
python 协程的学习记录的更多相关文章
- day-5 python协程与I/O编程深入浅出
基于python编程语言环境,重新学习了一遍操作系统IO编程基本知识,同时也学习了什么是协程,通过实际编程,了解进程+协程的优势. 一.python协程编程实现 1. 什么是协程(以下内容来自维基百 ...
- python协程详解,gevent asyncio
python协程详解,gevent asyncio 新建模板小书匠 #协程的概念 #模块操作协程 # gevent 扩展模块 # asyncio 内置模块 # 基础的语法 1.生成器实现切换 [1] ...
- python协程--asyncio模块(基础并发测试)
在高并发的场景下,python提供了一个多线程的模块threading,但似乎这个模块并不近人如意,原因在于cpython本身的全局解析锁(GIL)问题,在一段时间片内实际上的执行是单线程的.同时还存 ...
- Python协程与Go协程的区别二
写在前面 世界是复杂的,每一种思想都是为了解决某些现实问题而简化成的模型,想解决就得先面对,面对就需要选择角度,角度决定了模型的质量, 喜欢此UP主汤质看本质的哲学科普,其中简洁又不失细节的介绍了人类 ...
- 5分钟完全掌握Python协程
本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理 1. 协程相关的概念 1.1 进程和线程 进程(Process)是应用程序启动的实例,拥有代码.数据 ...
- Python协程与JavaScript协程的对比
前言 以前没怎么接触前端对JavaScript 的异步操作不了解,现在有了点了解一查,发现 python 和 JavaScript 的协程发展史简直就是一毛一样! 这里大致做下横向对比和总结,便于对这 ...
- Python 协程总结
Python 协程总结 理解 协程,又称为微线程,看上去像是子程序,但是它和子程序又不太一样,它在执行的过程中,可以在中断当前的子程序后去执行别的子程序,再返回来执行之前的子程序,但是它的相关信息还是 ...
- 终结python协程----从yield到actor模型的实现
把应用程序的代码分为多个代码块,正常情况代码自上而下顺序执行.如果代码块A运行过程中,能够切换执行代码块B,又能够从代码块B再切换回去继续执行代码块A,这就实现了协程 我们知道线程的调度(线程上下文切 ...
- 从yield 到yield from再到python协程
yield 关键字 def fib(): a, b = 0, 1 while 1: yield b a, b = b, a+b yield 是在:PEP 255 -- Simple Generator ...
随机推荐
- connect-falsh的用法
借鉴博客 http://yunkus.com/connect-flash-usage/
- 《逐梦旅程 WINDOWS游戏编程之从零开始》笔记4——Direct3D编程基础
第11章 Direct3D编程基础 2D游戏是贴图的艺术,3D游戏是渲染的艺术.这句话在我学过了之前的GDI编程之后,前一句算是有所体会,现在是来理解后一句的时候了. 安装DirectX SDK配置啥 ...
- “无法识别的配置节system.webServer”解决办法
在Winsows 2008 Server 上安装asp.net 1.1 的应用程序,在启用默认文档或者浏览目录时会向 web.config 文件添加 <system.webServer> ...
- Markdown 表情包
- 在浏览器中输入url地址 -> 显示主页的过程
-来自<图解HTTP> 最近在进行前端面试方面的一些准备,看了网上许多相关的文章,发现有一个问题始终绕不开: 在浏览器中输入URL到整个页面显示在用户面前时这个过程中到底发生了什么.仔细思 ...
- 总结分析Java常见的四种引用
从JDK1.2版本开始,把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期.这四种级别由高到低依次为:强引用.软引用.弱引用和虚引用. 1.强引用 本章前文介绍的引用实际上都是强引用, ...
- python 写文件write(string), writelines(list) ,读文件
read()方法用于直接读取字节到字符串中,可以接参数给定最多读取的字节数,如果没有给定,则文件读取到末尾. readline()方法读取打开文件的一行(读取下个行结束符之前的所有字节),然后整行,包 ...
- 【BZOJ 1901】【ZJU 2112】Dynamic Rankings
http://www.lydsy.com/JudgeOnline/problem.php?id=1901 重新用整体二分写了一下. 整体二分的思想详见论文. 貌似带修区间k大和静态区间k大都是\(O( ...
- POJ1067 取石子游戏 威佐夫博弈 博弈论
http://poj.org/problem?id=1067 有两堆石子,数量任意,可以不同.游戏开始由两个人轮流取石子.游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子:二是可 ...
- 【概率dp】【滚动数组】CDOJ1652 都市大飙车
转移方程很显然. 因为是多段图模型,所以可以滚动数组优化一维空间. #include<cstdio> #include<cstring> using namespace std ...