Если у меня есть сопрограмма, которая запускает задачу, которая не должна быть отменена, я заверну эту задачу в asyncio.shield()
.
Кажется, поведение cancel
и shield
не то, что ябудет ожидать.Если у меня есть задача, завернутая в shield
, и я отменяю ее, сопрограмма await
-ing немедленно возвращается из этого оператора await
, а не ожидает завершения задачи, как подсказывает shield
.Кроме того, задача, которая была запущена с shield
, продолжает выполняться, но ее будущее теперь отменено, что не await
-able.
Из документов :
за исключением того, что если сопрограмма, содержащая ее, отменяется, задание, выполняемое в чем-либо (), не отменяется.С точки зрения чего-либо () отмены не произошло.Несмотря на то, что вызывающий объект все еще отменяется, выражение «await» по-прежнему вызывает ошибку CancelledError.
В этих документах не обязательно указывается, что вызывающий объект потенциально отменен за до завершения вызываемого абонента,что является сердцем моей проблемы.
Каков правильный метод shield
задачи от отмены, а затем дождитесь ее завершения, прежде чем вернуться.
Было бы больше смысла, если asyncio.shield()
поднял asyncio.CancelledError
после выполнения задачи await
, но, очевидно, здесь есть другая идея, которую я не понимаю.
Вот простой пример:
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()