asyncio 在任务中捕获 TimeoutError
asyncio catch TimeoutError in Task
我有一个 asyncio.Task
需要在一段时间后取消。在取消之前,任务需要做一些清理。根据文档,我应该只能调用 task.cancel 或 asyncio.wait_for(coroutine, delay)
并在协程中拦截 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()
documentation for asyncio.wait_for
指定它将取消底层任务,然后从 wait_for
调用自身引发 TimeoutError
:
Returns result of the Future or coroutine. When a timeout occurs, it
cancels the task and raises asyncio.TimeoutError
.
你说的任务取消是正确的 can indeed be intercepted:
[Task.cancel
] arranges for a CancelledError
to be thrown into the wrapped
coroutine on the next cycle through the event loop. The coroutine then
has a chance to clean up or even deny the request using
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())
输出:
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
如您所见,现在 'timed out'
在 TimeoutError
被 wait_for
引发之前打印出来。
我有一个 asyncio.Task
需要在一段时间后取消。在取消之前,任务需要做一些清理。根据文档,我应该只能调用 task.cancel 或 asyncio.wait_for(coroutine, delay)
并在协程中拦截 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()
documentation for asyncio.wait_for
指定它将取消底层任务,然后从 wait_for
调用自身引发 TimeoutError
:
Returns result of the Future or coroutine. When a timeout occurs, it cancels the task and raises
asyncio.TimeoutError
.
你说的任务取消是正确的 can indeed be intercepted:
[
Task.cancel
] arranges for aCancelledError
to be thrown into the wrapped coroutine on the next cycle through the event loop. The coroutine then has a chance to clean up or even deny the request usingtry
/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())
输出:
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
如您所见,现在 'timed out'
在 TimeoutError
被 wait_for
引发之前打印出来。