在asyncio模型中,执行由事件循环调度和协调。要取消当前暂停的任务的执行,您基本上只需要不恢复它即可。虽然实践中会有一些差异,但理论上应该很明显,这使得取消暂停的任务变得简单。
同样,可以通过相同的方式设置每个单独的超时时间:每当您挂起协程以等待结果时,都需要提供超时值。事件循环将确保在达到超时时间并且任务尚未完成时取消等待任务。
以下是一些具体的示例:
>>> import asyncio
>>> loop = asyncio.get_event_loop()
>>> task = asyncio.ensure_future(asyncio.sleep(5))
>>> task.cancel()
>>> loop.run_until_complete(task)
Traceback (most recent call last):
...
concurrent.futures._base.CancelledError
在实际应用中,可能会使用类似以下代码的方式实现:
class Foo:
task = None
async def sleeper(self):
self.task = asyncio.sleep(60)
try:
await self.task
except concurrent.futures.CancelledError:
raise NotImplementedError
当此方法处于睡眠状态时,其他人可以调用 foo.task.cancel()
来唤醒协程并让它处理取消。另外,调用 sleeper()
的人也可以直接取消它,而不给它清理的机会。
设置超时同样很容易:
>>> loop.run_until_complete(asyncio.wait_for(asyncio.sleep(60), 5))
[ ... 5 seconds later ... ]
Traceback (most recent call last):
...
concurrent.futures._base.TimeoutError
尤其是在HTTP请求超时的情况下,参见aiohttp:
async def fetch_page(session, url):
with aiohttp.Timeout(10):
async with session.get(url) as response:
assert response.status == 200
return await response.read()
with aiohttp.ClientSession(loop=loop) as session:
content = loop.run_until_complete(fetch_page(session, 'http://python.org'))
每个对 fetch_page
的调用显然可以自己决定aiohttp.Timeout
的值,而每个独立的实例在达到超时时都会抛出自己的异常。