python – asyncio CancelledError和KeyboardInterrupt
发布时间:2020-12-20 10:33:36 所属栏目:Python 来源:网络整理
导读:我正在尝试两种方法来阻止无限循环运行: supervisor_1:以编程方式取消任务 supervisor_2:使用Ctrl C停止任务 虽然supervisor_2在中断时不会抛出任何错误,但我无法让supervisor_1获得任务被销毁但它正在等待!知道为什么吗? 这是代码: import asyncioimp
我正在尝试两种方法来阻止无限循环运行:
> supervisor_1:以编程方式取消任务 虽然supervisor_2在中断时不会抛出任何错误,但我无法让supervisor_1获得任务被销毁但它正在等待!知道为什么吗? 这是代码: 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',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).
你也不应该在任务中压制CancelledError. 阅读this answer,我试图展示处理任务的不同方式.例如,要取消某个任务并等待它取消,您可以执行以下操作: 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. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |