asyncio在Task中捕获TimeoutError

时间:2015-06-15 02:48:29

标签: python python-3.x python-asyncio

我有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()

1 个答案:

答案 0 :(得分:4)

documentation for asyncio.wait_for指定它将取消基础任务,然后从super.paintComponent调用本身提升TimeoutError

  

返回Future或coroutine的结果。当发生超时时,它   取消任务并引发wait_for

你认为任务取消正确can indeed be intercepted

  

[asyncio.TimeoutError]安排将Task.cancel投入到包装中   通过事件循环在下一个循环中的协程。那个协程   有机会清理甚至拒绝使用请求   CancelledError / 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之前就会打印出来。