Python3.10 Generator生成器Coroutine原生协程详解
作者:刘悦的技术博客 发布时间:2023-10-25 15:31:36
引言
普遍意义上讲,生成器是一种特殊的迭代器,它可以在执行过程中暂停并在恢复执行时保留它的状态。而协程,则可以让一个函数在执行过程中暂停并在恢复执行时保留它的状态,在Python3.10中,原生协程的实现手段,就是生成器,或者说的更具体一些:协程就是一种特殊的生成器,而生成器,就是协程的入门心法。
协程底层实现
我们知道,Python3.10中可以使用async和await关键字来实现原生协程函数的定义和调度,但其实,我们也可以利用生成器达到协程的效果,生成器函数和普通函数的区别在于,生成器函数使用 yield 语句来暂停执行并返回结果。例如,下面是一个使用生成器函数实现的简单协程:
def my_coroutine():
while True:
x = yield
print(x)
# 使用生成器函数创建协程
coroutine = my_coroutine()
# 启动协程
next(coroutine)
# 在协程中传入数据
coroutine.send(1)
coroutine.send(2)
coroutine.send(3)
程序返回:
➜ mydemo git:(master) ✗ /opt/homebrew/bin/python3.10 "/Users/liuyue/wodfan/work/mydemo/src/test.py"
1
2
3
在上面的代码中,生成器函数 my_coroutine 使用了一个无限循环来实现协程的逻辑。每当调用 send 方法时,协程就会从 yield 语句处恢复执行,并将传入的参数赋值给变量 x。
如此,就完成了协程执行-》阻塞-》切换-》回调的工作流模式。
当然,作为事件循环机制,协程服务启动可能无限期地运行,要关闭协程服务,可以使用生成器的close()方法。当一个协程被关闭时,它会生成GeneratorExit异常,该异常可以用生成器的方式进行捕获:
def my_coroutine():
try :
while True:
x = yield
print(x)
except GeneratorExit:
print("协程关闭")
# 使用生成器函数创建协程
coroutine = my_coroutine()
# 启动协程
next(coroutine)
# 在协程中传入数据
coroutine.send(1)
coroutine.send(2)
coroutine.send(3)
coroutine.close()
程序返回:
➜ mydemo git:(master) ✗ /opt/homebrew/bin/python3.10 "/Users/liuyue/wodfan/work/mydemo/src/test.py"
1
2
3
协程关闭
业务场景
在实际业务场景中,我们也可以使用生成器来模拟协程流程,主要体现在数据的IO流操作中,假设我们需要从本地往服务器传输数据,首先建立链接对象:
class Connection:
def __init__(self, addr):
self.addr = addr
def transmit(self, data):
print(f"X: {data[0]}, Y: {data[1]} sent to {self.addr}")
随后建立生成器函数:
def send_to_server(conn):
while True:
try:
raw_data = yield
raw_data = raw_data.split(' ')
coords = (float(raw_data[0]), float(raw_data[1]))
conn.transmit(coords)
except ConnectionError:
print("链接丢失,进行回调")
conn = Connection("重新连接v3u.cn")
利用生成器调用链接类的transmit方法进行数据的模拟传输,如果链接断开,则会触发回调重新连接,执行逻辑:
if __name__ == '__main__':
conn = Connection("v3u.cn")
sender = send_to_server(conn)
sender.send(None)
for i in range(1, 6):
sender.send(f"{100/i} {200/i}")
# 模拟链接断开
conn.addr = None
sender.throw(ConnectionError)
for i in range(1, 6):
sender.send(f"{100/i} {200/i}")
程序返回:
X: 100.0, Y: 200.0 sent to v3u.cn
X: 50.0, Y: 100.0 sent to v3u.cn
X: 33.333333333333336, Y: 66.66666666666667 sent to v3u.cn
X: 25.0, Y: 50.0 sent to v3u.cn
X: 20.0, Y: 40.0 sent to v3u.cn
链接丢失,进行回调
X: 100.0, Y: 200.0 sent to 重新连接v3u.cn
X: 50.0, Y: 100.0 sent to 重新连接v3u.cn
X: 33.333333333333336, Y: 66.66666666666667 sent to 重新连接v3u.cn
X: 25.0, Y: 50.0 sent to 重新连接v3u.cn
X: 20.0, Y: 40.0 sent to 重新连接v3u.cn
如此,我们就可以利用生成器的“状态保留”机制来控制网络链接突然断开的回调补救措施了。
所以说,协程就是一种特殊的生成器:
async def test():
pass
print(type(test()))
您猜怎么着?
<class 'coroutine'>
来源:https://juejin.cn/post/7181766056719941690


猜你喜欢
- 本文实例讲述了Python获取运行目录与当前脚本目录的方法。分享给大家供大家参考。具体实现方法如下:import osimport sys#
- dataclass语法一、 简介官方文档的地址为:https://docs.python.org/3.9/library/dataclass
- 问题背景查询MySQL中用逗号分隔的字段【a,b,c】是否包含【a】场景模拟现有表【ec_logicplace】,如下图所示:要求判断数值【
- 没有,用case when 来代替就行了. 例如,下面的语句显示中文年月 select getdate() as 日期,case month
- 当多个事件绑定了同一个命令,那么在命令内部根据不同的事件进行处理的时候,怎么确定哪个事件发生了呢,用下面的来检测,经过测试处理tab键和al
- 在用Linux(OS:Centos 7.2)时看到有一行代码是:export PYTHONPATH=$PYTHONPATH:/home/us
- 一、前言刚开始学Python的小伙伴可能会觉得每次写Python打开Cmd或者idle有点烦躁,没有代码补全也没有格式提示等。所以直接上手了
- 表单内有两个提交按钮,要实现当点击不同的提交按钮时,分别进行两个不同的处理过程,在这里有实现表单多按钮提交action的处理方法分享给大家。
- 人丑就要多读书,颜值不够知识来凑,至少你可以用书籍来武装你的大脑,拯救你的人生。TIOBE编程语言排行榜前20的语言入门书籍推荐
- 本篇介绍在执行MySQL线上变更时遇到的问题,表现为"更新JSON字段时,实际更新的值与SQL语句中的值不一致,JSON格式错误&
- 如何获取相邻数据因为项目,所以找到了一些资料并且总结了下关于获取相邻数据的方式。我只找到了以下的.../*获取id值与5相减绝对值最近的数据
- 绿色在黄色和蓝色(冷暖)之间,属于较中庸的颜色,这样使得绿色的性格最为平和、安稳、大度、宽容。是一种柔顺、恬静、满足、优美、受欢迎之色。也是
- MySQL多字段相同数据去重复MySQL多字段去重复实际上是单字段去重复的衍生,原理就是把多字段数据通过子查询合并为单字段的数据表,再通过单
- SQL一些语句执行后出现异常不会回滚MySQL回滚问题SQL中会隐式提交的操作:1、DDL语句:ALTER DATABASE、ALTER E
- 本文介绍了vue 模拟后台数据(加载本地json文件)调试,分享给大家,也给自己留个笔记首先创建一个本地json文件,放在项目中如下{ &q
- 一、subprocess以及常用的封装函数运行python的时候,我们都是在创建并运行一个进程。像Linux进程那样,一个进程可以fork一
- 在用csv.writer写入文件的时候发现中间有多余的空行。最早打开方式只是‘w',会出现多余的空行,网上建议使用binary形式‘
- 第一步:下载mysql驱动cmd进入创建好的django项目目录:使用命令pip install mysqlclient等待安装
- 之前已经简单介绍了Python正则表达式的基础与捕获,那么在这一篇文章里,我将总结一下正则表达式的贪婪/非贪婪特性。 贪婪默认情况
- 我们经常会用到表格数据,在做表格的时候,一般都喜欢隔行变色,使表格表现数据的时候非常的清晰。如图,我设计的一个表格表现的样式:在网上找到一个