如果我有一个协同程序,它运行一个不应该被取消的任务,我会将该任务包装为asyncio.shield().

似乎cancelshield的行为不是我所期望的.如果我将一个任务包装在shield中并取消它,那么await ing协程将立即从await语句返回,而不是像shield所建议的那样等待任务完成.此外,与shield一起运行的任务将继续运行,但它的future 将被取消,无法执行.

docs人中:

除非包含它的协同程序被取消,否则在something()中运行的任务不会被取消.从某事的Angular 来看,取消没有发生.尽管它的调用者仍然被取消,所以"wait"表达式仍然会引发CanceledError.

这些文件并没有强烈暗示来电者可能在被叫人结束时被取消,这是我的问题的核心.

什么是正确的方法来阻止任务取消,然后等待任务完成再返回.

如果asyncio.shield()await ed任务完成后提高了asyncio.CancelledError,这会更有意义,但显然这里还有一些我不理解的 idea .

下面是一个简单的例子:

import asyncio

async def count(n):
  for i in range(n):
    print(i)
    await asyncio.sleep(1)

async def t():
  try:
    await asyncio.shield(count(5))
  except asyncio.CancelledError:
    print('This gets called at 3, not 5')

  return 42

async def c(ft):
  await asyncio.sleep(3)

  ft.cancel()

async def m():
  ft = asyncio.ensure_future(t())
  ct = asyncio.ensure_future(c(ft))

  r = await ft

  print(r)

loop = asyncio.get_event_loop()
loop.run_until_complete(m())

# Running loop forever continues to run shielded task
# but I'd rather not do that
#loop.run_forever()

推荐答案

似乎cancelshield的行为不是我所期望的.如果我将一个任务包装在shield中并取消它,那么await ing协程将立即从await语句返回,而不是像shield所建议的那样等待任务完成.此外,与shield一起运行的任务将继续运行,但它的future 将被取消,无法执行.

从概念上讲,shield就像一件防弹背心,可以吸收子弹并保护佩戴者,但它本身会被撞击摧毁.shield接受取消,并将自己报告为已取消,当询问结果时,将提高CancelledError,但允许受保护的任务继续运行.(Artemiy的回答解释了实现过程.)

shield返回的对future 的取消可能以不同的方式实现,例如完全忽略取消请求.当前的方法确保取消"成功",即取消者无法判断取消实际上是被规避的.这是经过设计的,它使取消机制总体上更加一致.

什么是防止任务取消,然后等待任务完成再返回的正确方法

保留两个对象:原始任务和屏蔽任务.您将屏蔽任务传递给任何可能最终取消它的函数,然后等待原始任务.例如:

async def coro():
    print('starting')
    await asyncio.sleep(2)
    print('done sleep')

async def cancel_it(some_task):
    await asyncio.sleep(0.5)
    some_task.cancel()
    print('cancellation effected')

async def main():
    loop = asyncio.get_event_loop()
    real_task = loop.create_task(coro())
    shield = asyncio.shield(real_task)
    # cancel the shield in the background while we're waiting
    loop.create_task(cancel_it(shield))
    await real_task

    assert not real_task.cancelled()
    assert shield.cancelled()

asyncio.get_event_loop().run_until_complete(main())

代码等待任务完全完成,尽管其屏蔽被取消.

Python-3.x相关问答推荐

使用pythonnet和nicegui时无法pickle December对象

我想判断df_entry_log[AM_PM],并根据测试填充列

如何将多个字典合并到一个列中,并为不同的行使用相同的键

Pandas 根据条件增加Dataframe列

如何将从维基百科表中抓取的数据转换为字典列表?

添加任意数量的 pandas 数据框

在python内的powershell中转义$_

torch.stack([t1, t1, t1], dim=1)与torch.hstack([t1, t1, t1])之间有什么区别?

从 https://www.niftytrader.in/stock-options-chart/sbin 提取 SBIN 股票最大痛苦值的 Python 代码不起作用 - 我错过了什么?

在 python 中使用正则表达式在行尾查找特定元素

多进程:两个进程,一起杀死

numpy是如何添加@运算符的?

通过点和线计算CV2 Homography

在判断列表变量时如何判断特定列的值并分配加权整数值

无法在 macOS 上的 Anaconda3 python3.6 上安装 OpenCV3

Python 3:函数参数中的省略号?

用 numpy nan 查找列表的最大值

使用 python2 和 python3 创建一个 virtualenv

使用 Python 3 读取 CSV 文件

字典理解中的操作顺序