Eva*_*mas 3 python python-3.x python-asyncio
我有asyncio.Task一段时间需要取消。在取消之前,任务需要做一些清理工作。根据文档,我应该只能在协程中调用 task.cancel 或asyncio.wait_for(coroutine, delay)拦截 an asyncio.TimeoutError,但以下示例不起作用。我尝试过拦截其他错误并调用task.cancel,但都没有成功。我是否误解了取消任务的工作原理?
@asyncio.coroutine
def toTimeout():
try:
i = 0
while True:
print("iteration ", i, "......"); i += 1
yield from asyncio.sleep(1)
except asyncio.TimeoutError:
print("timed out")
def main():
#... do some stuff
yield from asyncio.wait_for(toTimeout(), 10)
#... do some more stuff
asyncio.get_event_loop().run_until_complete(main())
asyncio.get_event_loop().run_forever()
Run Code Online (Sandbox Code Playgroud)
的文档asyncio.wait_for指定它将取消基础任务,然后TimeoutError从wait_for调用本身引发:
返回 Future 或协程的结果。当发生超时时,它会取消任务并引发
asyncio.TimeoutError。
你是对的,任务取消确实可以被拦截:
[
Task.cancel] 安排CancelledError在事件循环的下一个循环中将 a 扔到包装的协程中。try然后,协程有机会使用//except清理甚至拒绝请求finally。
请注意,文档指定CancelledError将 放入协程中,而不是TimeoutError.
如果您进行调整,事情就会按照您期望的方式进行:
import asyncio
@asyncio.coroutine
def toTimeout():
try:
i = 0
while True:
print("iteration ", i, "......"); i += 1
yield from asyncio.sleep(1)
except asyncio.CancelledError:
print("timed out")
def main():
#... do some stuff
yield from asyncio.wait_for(toTimeout(), 3)
#... do some more stuff
asyncio.get_event_loop().run_until_complete(main())
Run Code Online (Sandbox Code Playgroud)
输出:
iteration 0 ......
iteration 1 ......
iteration 2 ......
timed out
Traceback (most recent call last):
File "aio.py", line 18, in <module>
asyncio.get_event_loop().run_until_complete(main())
File "/usr/lib/python3.4/asyncio/base_events.py", line 316, in run_until_complete
return future.result()
File "/usr/lib/python3.4/asyncio/futures.py", line 275, in result
raise self._exception
File "/usr/lib/python3.4/asyncio/tasks.py", line 238, in _step
result = next(coro)
File "aio.py", line 15, in main
yield from asyncio.wait_for(toTimeout(), 3)
File "/usr/lib/python3.4/asyncio/tasks.py", line 381, in wait_for
raise futures.TimeoutError()
concurrent.futures._base.TimeoutError
Run Code Online (Sandbox Code Playgroud)
正如您所看到的, now在引发'timed out'之前被打印。TimeoutErrorwait_for