Generator(生成器),入门初基,Coroutine(原生协程),登峰造极,Python3.10并发异步编程async底层实现
普遍意义上讲,生成器是一种特殊的迭代器,它可以在执行过程中暂停并在恢复执行时保留它的状态。而协程,则可以让一个函数在执行过程中暂停并在恢复执行时保留它的状态,在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'>
结语
诚然,生成器和协程也并非完全是一个概念,与生成器不同的是,协程可以被另一个函数(称为调用方)恢复执行,而不是只能由生成器本身恢复执行。这使得协程可以用来实现更复杂的控制流,因为它们可以在执行时暂停并在任意时刻恢复执行。
Generator(生成器),入门初基,Coroutine(原生协程),登峰造极,Python3.10并发异步编程async底层实现的更多相关文章
- 小议Python3的原生协程机制
此文已由作者张耕源授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 在最近发布的 Python 3.5 版本中,官方正式引入了 async/await关键字.在 asyncio ...
- Python 原生协程------asyncio
协程 在python3.5以前,写成的实现都是通过生成器的yield from原理实现的, 这样实现的缺点是代码看起来会很乱,于是3.5版本之后python实现了原生的协程,并且引入了async和aw ...
- 协程,greenlet原生协程库, gevent库
协程简介 协程(coroutine),又称为微线程,纤程,是一种用户级的轻量级线程.协程拥有自己的寄存器上下文和栈. 协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来时,恢复之前保存的上下文 ...
- Boost.Coroutine2:学习使用Coroutine(协程)
function(函数)routine(例程)coroutine (协程) 函数,例程以及协程都是指一系列的操作的集合. 函数(有返回值)以及例程(没有返回值)也被称作subroutine(子例程), ...
- Python3的原生协程(Async/Await)和Tornado异步非阻塞
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_113 我们知道在程序在执行 IO 密集型任务的时候,程序会因为等待 IO 而阻塞,而协程作为一种用户态的轻量级线程,可以帮我们解决 ...
- C#中的yield return与Unity中的Coroutine(协程)(下)
Unity中的Coroutine(协程) 估计熟悉Unity的人看过或者用过StartCoroutine() 假设我们在场景中有一个UGUI组件, Image: 将以下代码绑定到Image using ...
- python从入门到放弃之协程
协程 协程,又称微线程,纤程.英文名Coroutine. 协程的概念很早就提出来了,但直到最近几年才在某些语言(如Lua)中得到广泛应用. 子程序,或者称为函数,在所有语言中都是层级调用,比如A调用B ...
- 数据结构和算法(Golang实现)(6)简单入门Golang-并发、协程和信道
并发.协程和信道 Golang语言提供了go关键字,以及名为chan的数据类型,以及一些标准库的并发锁等,我们将会简单介绍一下并发的一些概念,然后学习这些Golang特征知识. 一.并发介绍 我们写程 ...
- 运筹帷幄决胜千里,Python3.10原生协程asyncio工业级真实协程异步消费任务调度实践
我们一直都相信这样一种说法:协程是比多线程更高效的一种并发工作方式,它完全由程序本身所控制,也就是在用户态执行,协程避免了像线程切换那样产生的上下文切换,在性能方面得到了很大的提升.毫无疑问,这是颠扑 ...
- python 协程(单线程中的异步调用)(转廖雪峰老师python教程)
协程,又称微线程,纤程.英文名Coroutine. 协程的概念很早就提出来了,但直到最近几年才在某些语言(如Lua)中得到广泛应用. 子程序,或者称为函数,在所有语言中都是层级调用,比如A调用B,B在 ...
随机推荐
- 离线安装chrome浏览器的postman插件
最近开始研究webapi相关的东西,看到chrome浏览器的有个postman插件挺好用的,但是安装包下载下来以后会出现这种情况,这时候我们可以把crx后缀的改成zip格式的然后解压,然后选择开发者模 ...
- 从零开始学Graph Database:什么是图
摘要:本文从零开始引导与大家一起学习图知识.希望大家可以通过本教程学习如何使用图数据库与图计算引擎.本篇将以华为云图引擎服务来辅助大家学习如何使用图数据库与图计算引擎. 本文分享自华为云社区<从 ...
- Vue3解决ElementPlus Drawer或弹出对话框不生效的问题
第一时间检查你是否还在使用 :visible.sync="drawer" 来绑定事件框的隐藏和显示,vue3.0 已经更改为通过 v-model 来绑定事件框的显示与隐藏.
- KVM导入Ubuntu Cloud 镜像创建虚机及调整磁盘大小
Ubuntu Cloud Images Ubuntu官网会给各种公有云平台提供cloud镜像, 例如AWS, MS Azure, Google Cloud, 以及本地虚机环境例如 QEMU, VMwa ...
- Linux中CentOS 7版本安装JDK、Tomcat、MySQL、lezsz、maven软件详解
软件安装 在Linux系统中,安装软件的方式主要有四种,这四种安装方式的特点如下: 安装方式 特点 二进制发布包安装 软件已经针对具体平台编译打包发布,只要解压,修改配置即可 rpm安装 软件已经按照 ...
- Windows开启关闭测试模式的方法(含开启测试模式失败的解决办法)
前言: 内含:Windows开启关闭测试模式的方法.开启测试模式失败的解决办法.win10进入bios的方式.BitLocker恢复方式. 对于互联网从业者来说 ...
- django 生产环境部署手册
Django 是 python 的 web 框架,以下是其部署到生产环境的详细步骤,包含 Apache 和 nginx 版本. 部署环境 操作系统:centeros7.3 数据库:MySQL5.6.5 ...
- CF452F等差子序列 & 线段树+hash查询区间是否为回文串
记录一下一个新学的线段树基础trick(真就小学生trick呗) 给你一个1到n的排列,你需要判断该排列内部是否存在一个3个元素的子序列(可以不连续),使得这个子序列是等差序列.\(n\) <= ...
- webpack优化项目
在使用vue 构建项目的时候 ,会用到vue.js, vue-router.js, 等库,通常打包的话会将这些公用的代码打包的一个文件中,导致该文件过大影响加载的速度.那么可以考虑使用cdn 加速的方 ...
- clickhouse在风控-风险洞察领域的探索与实践
一.风险洞察平台介绍 以Clickhouse+Flink实时计算+智能算法为核心架构搭建的风险洞察平台, 建立了全面的.多层次的.立体的风险业务监控体系,已支撑欺诈风险.信用风险.企业风险.小微风险. ...