__aexit__的键盘插入

时间:2018-07-09 11:56:04

标签: python async-await python-asyncio

__ enter__和__aexit__方法旨在确保清理, 但是在抛出键盘中断之后,不再调用__aexit__方法。 我可以想象这是由于“ with”语句不属于当前执行点的堆栈跟踪的事实(很自然的猜测)。 如何在asyncio中有效处理此问题?

编辑: 我创建了一些示例代码:

import asyncio

class manager:
    async def __aenter__(self):
        print("enter")


    async def __aexit__(self, exc_type, exc_val, exc_tb):
        print("exit")

async def func1():
    print("func1")
    async with manager():
        await asyncio.sleep(1000)

async def func2():
    print("func2")
    await asyncio.sleep(2)
    raise KeyboardInterrupt

loop = asyncio.get_event_loop()
loop.create_task(func1())
loop.create_task(func2())
loop.run_forever()

1 个答案:

答案 0 :(得分:3)

所有任务仍然存在,您只需要决定如何处理它们即可。如果您的任务表现良好,那么它应该像取消它们然后让它们运行直到完成一样简单。

例如

try:
    loop.run_forever()
except BaseException:
    all_tasks = asyncio.Task.all_tasks(loop=loop)
    for task in all_tasks:
        task.cancel()
    loop.run_until_complete(
        asyncio.gather(
            *all_tasks,
            loop=loop,
            return_exceptions=True # means all tasks get a chance to finish
        )
    )
    raise
finally:
    loop.close()

哪个会产生:

func1
enter
func2
exit
Traceback (most recent call last):
  File "C:\Users\User\Documents\python\asyncio_test.py", line 26, in <module>
    loop.run_forever()
  File "C:\Users\User\AppData\Local\Programs\Python\Python35-32\lib\asyncio\base_events.py", line 295, in run_forever
    self._run_once()
  File "C:\Users\User\AppData\Local\Programs\Python\Python35-32\lib\asyncio\base_events.py", line 1254, in _run_once
    handle._run()
  File "C:\Users\User\AppData\Local\Programs\Python\Python35-32\lib\asyncio\events.py", line 125, in _run
    self._callback(*self._args)
  File "C:\Users\User\AppData\Local\Programs\Python\Python35-32\lib\asyncio\tasks.py", line 301, in _wakeup
    self._step()
  File "C:\Users\User\AppData\Local\Programs\Python\Python35-32\lib\asyncio\tasks.py", line 239, in _step
    result = coro.send(None)
  File "C:\Users\User\Documents\python\asyncio_test.py", line 19, in func2
    raise KeyboardInterrupt
KeyboardInterrupt

如果您的任务表现不佳,则此实现可能会停止。一种这样的实现如下:

async def bad():
    while True:
        try:
            print('bad loop')
            await asyncio.sleep(0.5, loop=loop)
        except BaseException as e:
            print(repr(e))