协程asyncio_Python 异步模块 asyncio 中的协程与任务

协程(Coroutine)是允许执行被挂起、恢复、以及取消的程序。Python 3 中最初是使用 @asyncio.coroutine 装饰器和 yield from 关键字组合来实现协程。单词 yield 在这里并非在生成器(Generator)中所表示的“产出”,而是交通标志中所表达的“让步”之意。其实在生成器中也包含“让步”的意思,即把执行权交给调用者,生成器暂缓执行,等待调用者对生成的结果处理完成,再恢复生成器的执行。在异步程序中,yield 则是把当前的执行权交给事件循环中的其它协程。Python 3.5 开始 async/await 被引入,Python 3.7 开始成为保留关键字,让协程的使用更加方便和直观。本文使用 Python 3.8

使用 async def 定义一个协程:

async def main():print('hello coroutine')

协程具体可以分为使用 async def 定义的协程函数和调用协程函数返回的协程对象。调用一个协程函数并不会执行协程中的程序,而是只返回一个协程对象。

asyncio 提供了三种方式来执行协程:

1. 使用 asyncio.run()

run() 函数接收一个协程对象,在执行时,总会创建一个新的事件循环,并在结束后关闭循环。理想情况下,run() 函数应当被作为程序的总入口,并且只会被调用一次。如果同一线程中还有其它事件循环在运行,则此方法不能被调用。

async def main():print('hello coroutine')asyncio.run(main())

2. 使用 await 等待一个协程

await 的作用和 yield from 相同,即让出当前的执行权,等待的对象有结果返回时,再重新获得可以被继续执行的权利。

只有可等待对象(Awaitable object)才能被 await。除协程Coroutine)外,asyncio 还提供了两种可等待对象:任务Task)和期货Future)。

async def main():print('hello')await asyncio.sleep(1)await asyncio.sleep(2)print('coroutine')

上述程序在打印出 hello 后会等待 3 秒再打印出 coroutine。存在多个 await 时,会依次顺序执行,因为有两条 sleep() 语句,分别等待 1 秒和 2 秒,所以一共用时 3 秒。

3. 使用 asyncio.create_task() 创建 Task

create_task() 会把一个协程打包成一个任务(Task),并立即排入日程准备执行,函数返回值是打包完成的 Task 对象。

async def foo(n):await asyncio.sleep(n)async def main():task1 = asyncio.create_task(foo(1))task2 = asyncio.create_task(foo(2))print('hello')await task1await task2print('coroutine')

当使用 create_task() 时,创建的任务立即被加入到事件循环中,并不会阻塞当前的程序,所以上述程序在打印出 hello 后只需等待 2 秒就打印出 coroutine。

如上面所介绍,使用 create_task() 可以并发执行程序。asyncio 同时提供了几个函数用于方便地实现多任务并发执行:

1. asyncio.gather(*aws, return_exceptions=False)

gather() 函数接受传入多个可等待对象 aws,如果某个可等待对象是协程,则会被自动打包成 Taskgather() 返回结果是和 aws 传入顺序一致的列表。gather() 同时可以传入参数 return_exceptions 来处理异常,默认值为 False。如果为 False 时,执行过程中引发的首个异常会立即返回给等待 gather() 的任务,await 会直接结束等待并抛出异常,但是其它正常执行的 Task 不会被取消,这种情况适用于确保任务尽可能被执行完成,但是不关心返回结果,因为如果有任何一个任务出现异常,返回结果列表就不会顺利生成。如果把 return_exceptions 设为 True,异常会和正常结果一同被聚合进最终结果列表,适用于对结果有需求应用场景。

async def foo():return 'foo'async def bar():raise RuntimeError('fake runtime error')async def main():task1 = asyncio.create_task(foo())task2 = asyncio.create_task(bar())# return_exceptions=Trueresults = await asyncio.gather(task1, task2, return_exceptions=True)# 输出: ['foo', RuntimeError('fake runtime error')]print(results)# 返回结果的顺序和传参顺序一致assert isinstance(results[1], RuntimeError)# return_exceptions=Falsetry:results = await asyncio.gather(task1, task2, return_exceptions=False)# 此处打印并不会被执行, results 也未被赋值print(results)except RuntimeError as runtime_err:# 捕获异常并打印: fake runtime errorprint(runtime_err)

2. asyncio.wait(aws, *, timeout=None, return_when=ALL_COMPLETED)

wait() 接受 aws 任务集合传入, 然后并发执行。参数 return_when 用来控制返回条件,当 return_when=ALL_COMPLETED 时,会在所有任务完成后返回结果;当 return_when=FIRST_COMPLETED 时,任务集合中有一个任务完成就立即返回结果。timeout 参数用来控制超时时间,可以是整数或浮点数,以秒为单位。wait() 的返回值是 (done, pending) 元组,done 中包含运行完成的任务,pending 中包含未完成被挂起的任务。

async def foo():await asyncio.sleep(3)return 'foo'async def bar():await asyncio.sleep(1)return 'bar'async def main():# 有一个任务执行完成即返回, 总共耗时 1 秒done, pending = await asyncio.wait({foo(), bar()}, return_when=asyncio.FIRST_COMPLETED)# done 集合里包含打包成 Task 的 bar()print(f'done: {done}')# pendding 集合里包含打包成 Task 的 foo()print(f'pending: {pending}')# 所有任务执行完成后返回, 总共耗时 3 秒done, pending = await asyncio.wait({foo(), bar()}, return_when=asyncio.ALL_COMPLETED)# done 集合里包含被带打包成 Task 的 foo() 和 bar()print(f'done: {done}')# pending 集合为空print(f'pending: {pending}')# 所有任务执行完成, 但运行时间不能超 2 秒后返回, 总共耗时 2 秒done, pending = await asyncio.wait({foo(), bar()}, timeout=2, return_when=asyncio.ALL_COMPLETED)# done 集合里包含打包成 Task 的 bar()print(f'done: {done}')# pendding 集合里包含打包成 Task 的 foo()print(f'pending: {pending}')

3. asyncio.as_completed(aws)

as_completed() 接受 aws 集合,然后返回一个 Future 迭代器,遍历这个迭代器会依次遍历剩余可等待对象集合中最早完成的结果。

async def foo():await asyncio.sleep(2)return 'foo'async def bar():await asyncio.sleep(1)return 'bar'async def main():for fut in asyncio.as_completed({foo(), bar()}):earliest_result = await fut# 会依次打印 bar 和 foo, 因为 bar() 会更早执行完毕print(earliest_result)

上面介绍多任务并发时引入了超时的概念,超时也可以被应用在单独的一个任务中,使用 asyncio.wait_for(aw, timeout) 函数,该函数接受一个任务 aw 和超时时间 timeout,如果在限制时间内完成,则会正常返回,否则会被取消并抛出 asyncio.TimeoutError 异常。

为了防止任务被取消,可以使用 asyncio.shield(aw) 进行保护。shield() 会屏蔽外部取消操作,如果外部任务被取消,其内部正在执行的任务不会被取消,在内部看来取消操作并没有发生,由于内部仍正常执行,执行完毕后会触发 asyncio.CancelledError 异常,如果确保程序能忽略异常继续执行,需要在外部使用 try-except 捕获异常。如果在任务内部取消,则会被成功取消。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/333894.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ie8兼容性视图灰色修复_IE8网页显示不正常 用”兼容性视图”搞定

网页显示不正常,出现图片错位,文字跑远……等等,别急,试试IE8自带的”兼容性视图”功能吧!其实出现网页显示问题,一般不是您的电脑或者浏览器有问题,而是由于各网站开发标准不同,所以在不同的浏…

GAN对抗生成网络原始论文理解笔记

文章目录论文:Generative Adversarial Nets符号意义生成器(Generator)判别器(Discriminator)生成器和判别器的关系GAN的训练流程简述论文中的生成模型和判别模型GAN的数学理论最大似然估计转换为最小化KL散度问题定义PGP_GPG​全局最优论文:Generative A…

php cdi_CDI和lambda的策略模式

php cdi策略设计模式在运行时动态选择一种实现算法,一种策略。 该模式可用于根据情况选择不同的业务算法。 我们可以将不同的算法实现定义为单独的类。 或者,我们利用Java SE 8 lambda和函数,这些lambda和函数在此处用作轻量级策略实现。 C…

Linux 命令之 cp -- 复制文件或目录

文章目录一、命令介绍二、常用选项三、命令示例(一)复制某个目录到某个目录下(二)复制文件(三)复制文件到目标目录下,若存在文件则备份(四)复制某个目录的全部文件到某个…

向上累积频数怎么算_excel数据分析向上累计和向下累计怎么做呢

2016-07-08 00:25赵飞虎 客户经理一、Excel在分析性测试、复核中的运用注册会计师在分析审计风险确定重点审计领域、重要性水平和重大异常经济业务事项时,常常要对被审计单位的会计报表进行分析性测试和复核。在执行具体审计程序时,也常常要对本期数和上…

okta使用_使用Okta的单点登录保护您的Vert.x服务器

okta使用“我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕? 尝试使用Okta API进行托管身份验证,授权和多因素身份验证。 Vert.x是Spring生态系统中增长最快的元素之一,保护Vert.x服务器可…

Linux 命令之 make -- GNU的工程化编译工具

文章目录一、命令介绍二、常用选项三、命令示例(一)指定命令 make 的工作目录一、命令介绍 make 命令是 GNU 的工程化编译工具,用于编译众多相互关联的源代码文件,还可以编辑内核或模块,以实现工程化的管理&#xff0…

SDL2笔记

SDL2基本操作头文件主函数初始化创建窗口窗口暂停以及事件讲解销毁窗口(释放指针)并退出加载bmp图片新加载图片的方法(使用渲染、纹理)加载其他格式的图片头文件 #include "SDL.h" #include "SDL_image.h"主函数 int main(int argc,char* argv[]) //一定…

操作系统时间片轮换_《操作系统_时间片轮转RR进程调度算法》

转自:https://blog.csdn.net/houchaoqun_xmu/article/details/55540250时间片轮转RR进程调度算法一、概念介绍和案例解析时间片轮转法 - 基本原理:在早期的时间片轮转法中,系统将所有的就绪进程按先来先服务的原则排成一个队列,每次调度时&am…

java ee打印功能_Java EE 8的前5个新功能

java ee打印功能备受期待的Java Enterprise Edition 8版本具有两个令人兴奋的新API(JSON绑定1.0和Java EE Security 1.0),并且对当前API进行了改进(JAX-RS 2.1,Bean Validation 2.0,JSF 2.3,CDI…

SDL2事件笔记

SDL2事件窗口关闭的事件:鼠标事件鼠标点击事件鼠标移动事件键盘事件用SDL_PollEvent(&event)来检测是否有事件,用SDL_Event的实例属性event.type来获取事件。 窗口关闭的事件: SDL_QUIT鼠标事件 鼠标点击事件 鼠标点击事件&#xff1…

什么是复数

我们把形如 zabi(a、b均为实数)的数称为复数。其中,a 称为实部,b 称为虚部,i 称为虚数单位。当 z 的虚部 b=0 时,则 z 为实数;当 z 的虚部 b≠0 时,实部 a=0 …

qnx 设备驱动开发_QNX驱动开发——应用层与resource manger交互 | 学步园

QNX操作系统是一个类Unix实时操作系统,遵从POSIX规范,驱动程序具有良好的可移植性。编写任何驱动程序都会遇到同样的一个问题:应用程序与驱动程序之间是如何进行交互的。其实这个问题很简单,QNX有大量资料说明这一点。当客户端调用…

spring api层打包_Spring项目的按层打包已过时

spring api层打包我认为Spring应用程序不应该以逐层方法构造。 在我看来,按功能打包更有意义。 首先,让我简要描述每种方法。 “按层打包”(在非Java世界中为“按类型折叠”) 该项目结构根据源代码文件所属的体系结构层将其分为…

C++ Primer(第五版)第七章 类 部分答案

第七章 类练习7.2练习7.3练习7.4练习7.6练习7.7练习7.9练习7.14、7.15、7.22练习7.23、7.24、7.26练习7.27练习7.2 曾在 2.6.2 节的练习(第 76 页)中编写了一个 Sales_data类,请向这个类添加 combine 和 isbn 成员。 创建头文件sales.h #ifn…

arpanet(阿帕网)

“阿帕”(ARPA),是美国高级研究计划署(Advanced Research Project Agency)的简称。他的核心机构之一是信息处理技术办公室(IPTO Information Processing Techniques Office),一直在关…

mongodb数据库淘汰_mongodb 内存数据淘汰策略

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼About MongoMongoDB uses memory mapped files.This means the the operating system essentially controls what is paged in and out of memory (to and from disk).The RulesIf your indexes working set exceed memory, the l…

Markdown常用转义字符

如果字符无法正常输出,则在前面加\试试。 空格: 数学公式 数学公式要使用$$,需将公式放在两个$中间。 下标: _上标: ^分数:方法1:\frac{分子}{分母} 方法2:分子 \over 分母 对于\frac的方法…

互联网工程任务组(IETF)

国际互联网工程任务组(The Internet Engineering Task Force,简称 IETF)是一个公开性质的大型民间国际团体,汇集了与互联网架构和互联网顺利运作相关的网络设计者、运营者、投资人和研究人员,并欢迎所有对此行业感兴趣…

javafx 打印控件_Java的新视差控件(JavaFX)

javafx 打印控件介绍 视差是一种视觉效果,您可以组合以不同速度移动的两个分层图像以获得深度感。 想想一下,当您在道路上行驶时,您会看到附近的树木在快速移动,而距离较远的树木将沿同一方向移动但速度较慢,结果是您…