sha*_*ane 5 python-3.x python-asyncio
如果我有一个协程运行的任务不应被取消,我将把该任务包装在中asyncio.shield()。
看来的行为cancel而shield不是我所期望的那样。如果我包装了一个任务shield并取消了它,则await-ing协程将await立即从该语句返回,而不是像shield建议的那样等待任务完成。此外,与之shield一起运行的任务将继续运行,但其未来现在被取消await。
从文档:
除了如果包含协程的协程被取消,在something()中运行的任务不会被取消。从something()的角度来看,取消没有发生。尽管其调用方仍被取消,所以“ await”表达式仍会引发CancelledError。
这些文档并不强烈暗示在被叫者完成之前可能会取消呼叫者,这是我问题的核心。
shield从取消到执行任务,然后等待其完成后再返回的正确方法是什么?
如果在-ed任务完成后再asyncio.shield()提出,这会更有意义,但是显然这里还有其他我不理解的想法。asyncio.CancelledErrorawait
这是一个简单的示例:
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()
Run Code Online (Sandbox Code Playgroud)
看来的行为
cancel而shield不是我所期望的那样。如果我包装了一个任务shield并取消了它,则await-ing协程将await立即从该语句返回,而不是像shield建议的那样等待任务完成。此外,与之shield一起运行的任务将继续运行,但其未来现在被取消await。
从概念上讲,shield就像一个防弹背心,它吸收了子弹,但之后仍然无法使用。shield吸收取消,并报告自身为已取消,CancelledError在要求结果时引发一个,但允许受保护的任务继续运行。(Artemiy的答案解释了实现。)
屏蔽的取消可以以不同的方式实现,例如,通过完全忽略取消来实现,但当前的方法可确保取消“成功”,即取消器无法告知取消实际上是在绕开。这是设计使然,它使取消机制在整体上更加一致。
有什么合适的方法可以使任务免于取消,然后等待任务完成后再返回
通过保留两个对象:原始任务和被屏蔽的任务。您将受保护的任务传递给可能最终取消它的任何功能,然后等待原始任务。例如:
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())
Run Code Online (Sandbox Code Playgroud)
尽管已取消屏蔽,代码仍等待任务完全完成。
如果 asyncio.shield() 在 await-ed 任务完成后引发 asyncio.CancelledError 会更有意义,但显然这里还有一些我不明白的其他想法。
asyncio.shield
你可以在这里看到实现
屏蔽任务免于取消然后等待它完成后再返回的正确方法是什么
你应该屏蔽count(5)未来
async def t():
c_ft = asyncio.ensure_future(count(5))
try:
await asyncio.shield(c_ft)
except asyncio.CancelledError:
print('This gets called at 3, not 5')
await c_ft
return 42
Run Code Online (Sandbox Code Playgroud)
或t()未来
async def t():
await count(5)
return 42
async def m():
ft = asyncio.ensure_future(t())
shielded_ft = asyncio.shield(ft)
ct = asyncio.ensure_future(c(shielded_ft))
try:
r = await shielded_ft
except asyncio.CancelledError:
print('Shield cancelled')
r = await ft
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1949 次 |
| 最近记录: |