Python 异步编程原理篇之新旧协程实现对比

协程的发展流程
再来回顾一下协程的发展流程:
python2.5 为生成器引用.send()、.throw()、.close()方法
python3.3 为引入yield from,可以接收返回值,可以使用yield from定义协程
Python3.4 加入了asyncio模块
Python3.5 增加async、await关键字,在语法层面的提供支持
python3.7 使用 async def + await 的方式定义协程
python3.10 移除 以 yield from 的方式定义协程
旧协程是指以yield、yield from等生成器语法为基础的协程实现
新协程是指以asyncio、async、await等关键字为基础的协程实现
两种协程的实现方式在协程发展史上有一段交集,并且旧协程基于生成器的协程语法让生成器和协程两个概念混淆,所以对学习者会造成一定的困扰。本篇主要说明两种协程的实现方式的差异。
旧协程回顾
旧协程以yield关键字为核心,通过yield关键提供的代码执行暂停、恢复的能力,实现函数交替的执行,cpu的转让等能力。
import time
def consume():
r = ''
while True:
n = yield r
print(f'[consumer] 开始消费 {n}...')
time.sleep(1)
r = f'{n} 消费完成'
def produce(c):
next(c)
n = 0
while n < 5:
n = n + 1
print(f'[producer] 生产了 {n}...')
r = c.send(n)
print(f'[producer] consumer return: {r}')
c.close()
if __name__=='__main__':
c = consume()
produce(c)
执行结果:
[producer] 生产了 1...
[consumer] 开始消费 1...
[producer] consumer return: 1 消费完成
[producer] 生产了 2...
[consumer] 开始消费 2...
[producer] consumer return: 2 消费完成
[producer] 生产了 3...
[consumer] 开始消费 3...
[producer] consumer return: 3 消费完成
[producer] 生产了 4...
[consumer] 开始消费 4...
[producer] consumer return: 4 消费完成
[producer] 生产了 5...
[consumer] 开始消费 5...
[producer] consumer return: 5 消费完成
结果分析:
当消费者consume执行到n = yield r时,流程暂停,将cpu交还给调用方produce。
在asyncio初识篇中提到过,协程最重要的两个因素是事件循环+ 任务。用yield实现的协程中,consume和 produce中的 while循环共同作用下实现了一个事件循环的功能,yield 和 send实现了任务的暂停和继续执行。
总结来说协程需要的两个能力事件循环和任务暂停和继续,在旧协程中的实现分别是:
- 事件循环通过手动编写while循环代码实现
- 代码暂停继续执行通过yield生成器的能力实现
新协程回顾
新协程是asyncio、async、await等关键字实现的。新协程是基于事件循环机制实现的,核心能力包括事件循环,任务,回调机制等。三者提供的能力分别是
- asyncio 提供了事件循环
- async 提供了协程标识
- await 提供了流程挂起能力
import asyncio
async def coro1():
print("start coro1")
await asyncio.sleep(2)
print("end coro1")
async def coro2():
print("start coro2")
await asyncio.sleep(1)
print("end coro2")
# 创建事件循环
loop = asyncio.get_event_loop()
# 创建任务
task1 = loop.create_task(coro1())
task2 = loop.create_task(coro2())
# 运行协程
loop.run_until_complete(asyncio.gather(task1, task2))
# 关闭事件循环
loop.close()
结果
start coro1
start coro2
end coro2
end coro1
结果分析:
当coro1执行到 await asyncio.sleep(2)时,流程挂起,将cpu交还给事件循环,等待事件循环的下一次调度,而事件循环调度到coro2继续执行。
协程的两个重要能力事件循环和 任务暂停和继续 ,分别的实现者:
- 事件循环通过asyncio提供的loop实现
- 程序挂起通过 await 关键字实现
新酒协程实现的对比
asyncio 和 yield 是用于实现异步编程的两种不同的机制。
yield 是一种用于生成器(Generator)函数的关键字,用于创建可暂停和恢复执行的函数。当一个函数中包含 yield 语句时,它会返回一个生成器对象,可以通过调用生成器的 next() 方法或使用 for 循环来逐步迭代生成器函数中的值。
通过使用 yield,我们可以将一个函数分割成多个代码块,并在每个代码块之间进行切换执行。这使得我们可以在函数执行过程中临时挂起函数的执行,然后再次恢复执行。
asyncio 是 Python 提供的标准库,用于编写异步代码。它基于事件循环(Event Loop)模式,允许我们在单线程中处理多个并发任务,并通过协程(Coroutine)来管理异步操作。
asyncio 使用了 async 和 await 这两个关键字来定义协程函数。在协程函数中可以使用 await 关键字来暂停当前协程的执行,等待某个异步操作的完成,然后恢复执行。
总结来说:
旧协程:通过yield关键字的暂停和恢复执行的能力实现协程
新协程:通过事件循环机制,await关键字挂起流程能力实现协程
await 和 yield 的关系
await 关键字和 yield 关键字都可以用于控制流的暂停和恢复,都属于python的关键字,但是它们在协程的实现上有所不同。
相同点:
- 控制流暂停和恢复:无论是
await还是yield,它们都可以使代码在某个点暂停执行,并在稍后的时间点继续执行。 - 协程支持:
await和yield都与协程(Coroutine)密切相关。它们都能够用于定义和管理协程,使得异步代码的编写更加简单和易读。
区别:
- 语法差异:
await是 Python 3.5 引入的关键字,用于异步函数中暂停执行等待异步操作完成。而yield是早期协程的关键字,主要用于生成器(Generator)函数,用于创建迭代器和实现惰性计算,早期通过生成器的能力来实现协程。 - 语义:
await表示当前协程需要等待一个异步操作的完成,并挂起执行,让其他任务有机会执行。yield是将执行的控制权交给调用方,同时保存函数的状态,以便在下次迭代时从上一次暂停的位置恢复执行。await将程序挂起,让事件循环调度新的任务。yield将程序挂起,等待调用方的下一步指令。
- 上下文:
await必须在异步上下文中使用,例如在异步函数中或者在async with块中。而yield可以在普通函数中使用,即使没有使用协程的上下文。 - 返回值:
yield返回生成器对象,通过调用next()方法或使用for循环逐步迭代生成器中的值。而await返回一个可等待对象(Awaitable),它可以是Future、Task、Coroutine等。
总结:
await 不是通过 yield 来实现的程序暂停和执行,两者有相似的能力,但完全没有调用关系,都是属于python关键字。
await适用于异步编程场景,用于等待异步操作的完成,同时支持更灵活的协程管理。yield则主要用于生成器函数,用于实现迭代器和惰性计算。
它们在应用场景和语法上存在一些差异,但都为我们提供了控制流的暂停和恢复的能力。
以上就是新旧协程的实现方法,对比了两种协程的实现方法,比较了yield关键字既作为生成器又实现协程有点混淆的用法,比较了都可以暂停恢复的关键字yield和await。这些内容是协程原理的核心知识,理解有难度。
Python 异步编程原理篇之新旧协程实现对比的更多相关文章
- python并发编程之进程、线程、协程的调度原理(六)
进程.线程和协程的调度和运行原理总结. 系列文章 python并发编程之threading线程(一) python并发编程之multiprocessing进程(二) python并发编程之asynci ...
- Python并发编程之从生成器使用入门协程(七)
大家好,并发编程 进入第七篇. 从今天开始,我们将开始进入Python的难点,那就是协程. 为了写明白协程的知识点,我查阅了网上的很多相关资料.发现很难有一个讲得系统,讲得全面的文章,导致我们在学习的 ...
- 深入理解 Python 异步编程(上)
http://python.jobbole.com/88291/ 前言 很多朋友对异步编程都处于"听说很强大"的认知状态.鲜有在生产项目中使用它.而使用它的同学,则大多数都停留在知 ...
- python 异步编程
Python 3.5 协程究竟是个啥 Yushneng · Mar 10th, 2016 原文链接 : How the heck does async/await work in Python 3.5 ...
- 最新Python异步编程详解
我们都知道对于I/O相关的程序来说,异步编程可以大幅度的提高系统的吞吐量,因为在某个I/O操作的读写过程中,系统可以先去处理其它的操作(通常是其它的I/O操作),那么Python中是如何实现异步编程的 ...
- 这篇文章讲得精彩-深入理解 Python 异步编程(上)!
可惜,二和三现在还没有出来~ ~~~~~~~~~~~~~~~~~~~~~~~~~ http://python.jobbole.com/88291/ ~~~~~~~~~~~~~~~~~~~~~~~~~~ ...
- JavaScript异步编程原理
众所周知,JavaScript 的执行环境是单线程的,所谓的单线程就是一次只能完成一个任务,其任务的调度方式就是排队,这就和火车站洗手间门口的等待一样,前面的那个人没有搞定,你就只能站在后面排队等着. ...
- 深入理解Python异步编程(上)
本文代码整理自:深入理解Python异步编程(上) 参考:A Web Crawler With asyncio Coroutines 一.同步阻塞方式 import socket def blocki ...
- Python 异步编程笔记:asyncio
个人笔记,不保证正确. 虽然说看到很多人不看好 asyncio,但是这个东西还是必须学的.. 基于协程的异步,在很多语言中都有,学会了 Python 的,就一通百通. 一.生成器 generator ...
- Python并发编程理论篇
Python并发编程理论篇 前言 其实关于Python的并发编程是比较难写的一章,因为涉及到的知识很复杂并且理论偏多,所以在这里我尽量的用一些非常简明的语言来尽可能的将它描述清楚,在学习之前首先要记住 ...
随机推荐
- 颠覆了!eShop跟随.Net 8迎来重磅升级,微服务架构与GPT的完美结合!
.Net 8正式发布了,发布了诸多重大的新功能.新特性! .Net 8新增的功能带来诸多惊喜,还未一一体验完毕呢,我又发现了跟随.Net 8的发布,eShop也迎来重磅升级! eShop一直以来都是微 ...
- 使用 LCM LoRA 4 步完成 SDXL 推理
LCM 模型 通过将原始模型蒸馏为另一个需要更少步数 (4 到 8 步,而不是原来的 25 到 50 步) 的版本以减少用 Stable Diffusion (或 SDXL) 生成图像所需的步数.蒸馏 ...
- 记一次 RestTemplate 请求失败问题的排查 → RestTemplate 默认会对特殊字符进行转义
开心一刻 今天中午,侄子在沙发上玩手机,他妹妹屁颠屁颠的跑到他面前 小侄女:哥哥,给我一块钱 侄子:叫妈给你 小侄女朝着侄子,毫不犹豫的叫到:妈! 侄子:不是,叫妈妈给你 小侄女继续朝他叫到:妈妈 侄 ...
- 【Java】Java中StringBuilder()成员方法append()和toString()
StringBuilder就相当于C++的String长度可变,用于构造字符串对象,内部使用自动扩容的数组操作字符串数据. StringBuilder和StringBuffer使用的是相同的API[区 ...
- AntDesignBlazor示例——新建项目
本示例是AntDesign Blazor的入门示例,在学习的同时分享出来,以供新手参考. 1. 开发环境 VS2022 17.8.2 .NET8 AntDesign 0.16.2 2. 学习目标 创建 ...
- 聊聊GLM基座模型的理论知识
概述 大模型有两个流程:预训练和推理. 预训练是在某种神经网络模型架构上,导入大规模语料数据,通过一系列的神经网络隐藏层的矩阵计算.微分计算等,输出权重,学习率,模型参数等超参数信息. 推理是在预训练 ...
- Oracle-lsnrctl监听进程控制
LSNRCTL> help The following operations are available An asterisk (*) denotes a modifier or extend ...
- Asp.net core Webapi 项目如何优雅地使用内存缓存
前言 缓存是提升程序性能必不可少的方法,Asp.net core 支持多级缓存配置,主要有客户端缓存.服务器端缓存,内存缓存和分布式缓存等.其中客户端缓和服务器端缓存在使用上都有比较大的限制,而内存缓 ...
- Roaring bitmaps
Roaring bitmaps 最近看一篇文章,里面涉及到使用roaring bitmaps来推送用户广告并通过计算交集来降低用户广告推送次数.本文给出roaring bitmaps的原理和基本用法, ...
- [转]NLog学习笔记
配置文件 NLog所有的配置信息都可以写到一个单独的xml文件中,也可以在程序代码中进行配置. 配置文件位置 启动的时候,NLog会试图查找配置文件完成自动配置,查找的文件依次如下(找到配置信息则结束 ...