Python 异步之如何保护任务免于取消详解
作者:冷冻工厂 发布时间:2022-08-04 05:03:26
Asyncio 任务可以通过调用它们的 cancel() 方法来取消。我们可以通过将任务包装在对 asyncio.shield() 的调用中来保护任务不被取消。
让我们仔细看看。
1. 什么是 Asyncio shield()
asyncio.shield() 函数在 Future 中包装了一个可等待对象,它将吸收要取消的请求。
这意味着被屏蔽的未来可以传递给可能尝试取消它的任务,并且取消请求看起来像是成功的,除了被屏蔽的任务或协程将继续运行。
它可能在 asyncio 程序中很有用,其中某些任务可以取消,但其他任务(可能具有更高优先级)则不能。
它也可能在某些任务可以安全取消的程序中很有用,例如那些在设计时考虑了 asyncio 的任务,而其他任务则不能安全终止,因此必须避免取消。
现在我们知道了 asyncio.shield() 是什么,让我们看看如何使用它。
2. 如何使用 Asyncio shield()
asyncio.shield() 函数将保护另一个任务或协程不被取消。它以一个可等待对象作为参数并返回一个 asyncio.Future 对象。
然后可以直接等待 Future 对象或将其传递给另一个任务或协程。
...
# shield a task from cancellation
shielded = asyncio.shield(task)
# await the shielded task
await shielded
返回的 Future 可以通过调用 cancel() 方法取消。
如果内部任务正在运行,请求将被报告为成功。
...
# cancel a shielded task
was_canceld = shielded.cancel()
任何等待 Future 对象的协程都会引发 asyncio.CancelledError,这可能需要处理。
...
try:
# await the shielded task
await asyncio.shield(task)
except asyncio.CancelledError:
# ...
重要的是,对 Future 对象的取消请求不会传播到内部任务。这意味着取消请求被护盾吸收了。
...
# create a task
task = asyncio.create_task(coro())
# create a shield
shield = asyncio.shield(task)
# cancel the shield (does not cancel the task)
shield.cancel()
如果协程被提供给 asyncio.shield() 函数,它将被包装在 asyncio.Task() 中并立即调度。
这意味着不需要等待屏蔽来让内部协程运行。
如果被屏蔽的任务被取消,取消请求将向上传播到屏蔽,屏蔽也将被取消。
...
# create a task
task = asyncio.create_task(coro())
# create a shield
shield = asyncio.shield(task)
# cancel the task (also cancels the shield)
task.cancel()
现在我们知道如何使用 asyncio.shield() 函数,让我们看一些有效的例子。
3. 示例
我们可以探索如何使用 asyncio.shield() 来保护任务不被取消。
在这个例子中,我们定义了一个简单的协程任务,它接受一个整数参数,休眠一秒钟,然后返回参数。然后可以创建协程并将其安排为任务。
我们可以定义第二个协程,它接受一个任务,休眠几分之一秒,然后取消提供的任务。
在主协程中,我们可以屏蔽第一个任务,然后将其传递给第二个任务,然后等待被屏蔽的任务。
期望是屏蔽将被取消并保持内部任务完好无损。取消将中断主协程。我们可以在程序结束时检查内部任务的状态,我们希望它已经正常完成,而不管屏蔽上的取消请求如何。
# SuperFastPython.com
# example of using asyncio shield to protect a task from cancellation
import asyncio
# define a simple asynchronous
async def simple_task(number):
# block for a moment
await asyncio.sleep(1)
# return the argument
return number
# cancel the given task after a moment
async def cancel_task(task):
# block for a moment
await asyncio.sleep(0.2)
# cancel the task
was_cancelled = task.cancel()
print(f'cancelled: {was_cancelled}')
# define a simple coroutine
async def main():
# create the coroutine
coro = simple_task(1)
# create a task
task = asyncio.create_task(coro)
# created the shielded task
shielded = asyncio.shield(task)
# create the task to cancel the previous task
asyncio.create_task(cancel_task(shielded))
# handle cancellation
try:
# await the shielded task
result = await shielded
# report the result
print(f'>got: {result}')
except asyncio.CancelledError:
print('shielded was cancelled')
# wait a moment
await asyncio.sleep(1)
# report the details of the tasks
print(f'shielded: {shielded}')
print(f'task: {task}')
# start
asyncio.run(main())
运行示例首先创建 main() 协程并将其用作应用程序的入口点。创建任务协程,然后将其包装并安排在任务中。然后该任务就不会被取消。
然后将屏蔽的任务传递给 cancel_task() 协程,该协程包装在任务中并进行调度。主协程然后等待受保护的任务,该任务需要 CancelledError 异常。
任务运行片刻然后休眠。取消任务运行片刻,休眠,恢复然后取消屏蔽任务。取消请求报告它已成功。
这会在受保护的 Future 中引发 CancelledError 异常,但不会在内部任务中引发。
main() 协程恢复并响应 CancelledError 异常,报告一条消息。然后它会睡一会儿。任务恢复、完成并返回一个值。
最后,main() 协程恢复,并报告被屏蔽的未来和内部任务的状态。我们可以看到屏蔽的未来被标记为已取消,而内部任务被标记为正常完成并提供返回值。
此示例突出显示了如何使用防护罩来成功保护内部任务不被取消。
cancelled: True
shielded was cancelled
shielded: <Future cancelled>
task: <Task finished name='Task-2' coro=<simple_task() done, defined at ...> result=1>
来源:https://juejin.cn/post/7204799176936570941
猜你喜欢
- 记录一下Linux虚拟机下MySQL安装配置方法一、 下载mysql5.7http://mirrors.sohu.com/mysql/MyS
- 要想在不宽裕的页面展现丰富的内容,现在通用的做法使用tab,在一块区域通过tab切换来更换该区域的内容。这篇文章分析了tab设计很在理,今天
- 一、构造dataframeimport pandas as pdimport numpy as npdf=pd.DataFrame(np.a
- 我们在网页开发过程中经常会有打印页面的需求,通过JS来实现的方法有很多,这里我做了一个整理,供大家参考。方式一:window.print()
- python脚本替换指定行实现步骤 本文主要介
- 背景 还是学院和专业的关系,我需要保持点击提交按钮后,页面select中继续维持提交前的值 网上有几种办法,要么通过url跳转时候附带参数形
- 前言:内容提要:本文比较了 Python 中用于列表排序的两种函数 sort() 和 sorted(),帮助您选择合适的排序函数。对列表排序
- Python提取html中文本到txt正则去标签方式# -*- coding: utf-8 -*-import redef html_tag
- 一.什么是事务在MySQL中的事务(Transaction)是由存储引擎实现的,在MySQL中,只有InnoDB存储引擎才支持事务。事务处理
- 前言大家都知道,Python自带的datetime库提供了将datetime转为ISO 8610格式的函数,但是对于时间间隔(inteval
- 数学模块import mathceil -- 上取整对一个数向上取整(进一法),取相邻最近的两个整数的最大值。import mathres
- 本文实例讲述了django框架创建应用操作。分享给大家供大家参考,具体如下:18.1.5 安装Django安装Djangonod
- 1. go的依赖管理发展GOPATH 所有的依赖都放置在同一路径下,可以复用下载的依赖,但是当不同项目需要依赖不同版本的依赖时,就很容易出现
- 场景:服务器数据库需要实现每天定时备份1.首先确定备份脚本放置位置个人放置在 /usr/local/backup文件
- 不是说while就不用,比如前面所列举而得那个猜数字游戏,在业务逻辑上,用while就更容易理解(当然是限于那个游戏的业务需要而言)。另外,
- 本文实例讲述了python中pass语句用法。分享给大家供大家参考。具体分析如下:1、空语句 do nothing2、保证格式完整3、保证语
- 本文实例为大家分享了python文件写入write()的操作的具体代码,供大家参考,具体内容如下filename = 'pragra
- 开始一个组件,毫无目的的写代码是一个不好的习惯,要经历 分析 => 抽象 => 实现 => 应用 四个阶段。组件DEMO地
- 雪花算法是在一个项目体系中生成全局唯一ID标识的一种方式,偶然间看到了Python使用雪花算法不尽感叹真的是太便捷了。它生成的唯一ID的规则
- python3 判断空列表@(python3)有个判断列表是否为空的需求,试了好多方式,比如:a = []if a is not None: