我正在尝试2种方法来阻止无限循环运行:
虽然 supervisor_2 不会引发中断时,在任何错误,我不能让 supervisor_1 从得到Task was destroyed but it is pending!。知道为什么吗?
Task was destroyed but it is pending!
这是代码:
import asyncio import aioredis from functools import partial class Listener: def __init__(self, redis_conn): self.redis_conn = redis_conn async def forever(self, loop_name): counter = 0 try: while True: print('{}: {}'.format(loop_name, counter)) counter += 1 await asyncio.sleep(1) except asyncio.CancelledError: print('Task Cancelled') self.redis_conn.close() await self.redis_conn.wait_closed() async def supervisor_1(redis_conn): redis_conn = await redis_conn l = Listener(redis_conn) task = asyncio.ensure_future( asyncio.gather(l.forever('loop_1'), l.forever('loop_2'))) await asyncio.sleep(2) task.cancel() async def supervisor_2(redis_conn): redis_conn = await redis_conn l = Listener(redis_conn) await asyncio.gather(l.forever('loop_1'), l.forever('loop_2')) if __name__ == '__main__': redis_conn = aioredis.create_pool(('localhost', 5003), db=1) loop = asyncio.get_event_loop() run = partial(supervisor_2, redis_conn=redis_conn) task = asyncio.ensure_future(run()) try: loop.run_until_complete(task) except KeyboardInterrupt: print('Interruped !') task.cancel() loop.run_forever() finally: loop.close()
@update :
感谢@Gerasimov,这是一个可以解决此问题的版本,但仍会不时在KeyboardInterrupt上引发错误:
async def supervisor(redis_conn): redis_conn = await redis_conn l = Listener(redis_conn) task = asyncio.ensure_future( asyncio.gather(l.forever('loop_1'), l.forever('loop_2')) ) await asyncio.sleep(10) task.cancel() with suppress(asyncio.CancelledError): await task async def kill_tasks(): pending = asyncio.Task.all_tasks() for task in pending: task.cancel() with suppress(asyncio.CancelledError): await task
和
if __name__ == '__main__': redis_conn = aioredis.create_pool(('localhost', 5003), db=1) loop = asyncio.get_event_loop() run = partial(supervisor, redis_conn=redis_conn) task = asyncio.ensure_future(run()) try: loop.run_until_complete(task) except KeyboardInterrupt: print('Interruped !') loop.run_until_complete(kill_tasks()) finally: loop.close()
task.cancel()本身并没有完成任务:它只是说CancelledError应该在其中提出的任务并立即返回。您应该调用它并等待任务实际上被取消(它会引发CancelledError)。
task.cancel()
CancelledError
您也不应压制CancelledError内部任务。
在尝试显示不同的任务处理方式的地方,请阅读此答案。例如,要取消某些任务并等待其取消,您可以执行以下操作:
from contextlib import suppress task = ... # remember, task doesn't suppress CancelledError itself task.cancel() # returns immediately, we should await task raised CancelledError. with suppress(asyncio.CancelledError): await task # or loop.run_until_complete(task) if it happens after event loop stopped # Now when we awaited for CancelledError and handled it, # task is finally over and we can close event loop without warning.