gpt4 book ai didi

python-3.x - python asyncio - 如何等待取消的屏蔽任务?

转载 作者:行者123 更新时间:2023-12-03 14:36:03 27 4
gpt4 key购买 nike

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

似乎是 cancel 的行为和 shield不是我所期望的。如果我有一个包裹在 shield 中的任务我取消了它,await -ing 协程从 await 返回立即声明而不是等待任务完成为 shield会建议。此外,使用 shield 运行的任务继续运行但它的 future 现在被取消了 await -有能力的。

来自 docs :

except that if the coroutine containing it is cancelled, the Task running in something() is not cancelled. From the point of view of something(), the cancellation did not happen. Although its caller is still cancelled, so the “await” expression still raises a CancelledError.



这些文档并不强烈暗示在被调用者完成之前调用者可能被取消,这是我的问题的核心。
shield的正确方法是什么?取消任务,然后等待它完成后再返回。

如果 asyncio.shield() 会更有意义提出了 asyncio.CancelledErrorawait -ed 任务已经完成,但显然这里还有一些我不明白的其他想法。

这是一个简单的例子:
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()

最佳答案

It seems the behavior of cancel and shield is not what I would expect. If I have a task wrapped in shield and I cancel it, the await-ing coroutine returns from that await statement immediately rather than awaiting for the task to finish as shield would suggest. Additionally, the task that was run with shield continues to run but its future is now cancelled an not await-able.



概念 shield就像防弹背心,吸收子弹,保护穿着者,但自身却被撞击毁坏。 shield吸收取消,并报告自己已取消,引发 CancelledError当询问结果时,但允许 protected 任务继续运行。 (Artemiy 的回答解释了实现。)

取消由 shield 返回的 future 可以以不同的方式实现,例如通过完全忽略取消请求。当前的方法确保取消“成功”,即取消者无法判断取消实际上已被规避。这是设计使然,它使取消机制在整体上更加一致。

What is the proper method to shield a task from cancellation and then wait for it to complete before returning



通过保留两个对象:原始任务和屏蔽任务。您将屏蔽任务传递给可能最终取消它的任何函数,然后等待原始任务。例如:
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 - python asyncio - 如何等待取消的屏蔽任务?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52505794/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com