__ 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()
答案 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))