2015-06-15 72 views
1

我有一個asyncio.Task,我需要在一段時間後取消。取消之前,該任務需要進行一些清理。根據文檔,我應該能夠調用task.cancel或asyncio.wait_for(coroutine, delay)並攔截協程中的asyncio.TimeoutError,但以下示例不起作用。我嘗試攔截其他錯誤,並調用task.cancel來代替,但都沒有奏效。我誤解了取消任務的方式嗎?asyncio catch任務中的TimeoutError

@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() 

回答

3

documentation for asyncio.wait_for規定,將取消基礎任務,然後從wait_for調用本身提高TimeoutError:未來或協程

返回結果。發生超時時, 取消該任務並提出asyncio.TimeoutError

而且你是正確的,任務取消can indeed be intercepted

[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前打印由wait_for提高。