Python异步IO任务中未处理异常后的整理
在包含多个任务的python aysncio应用程序中,报告其中一个任务中未处理的异常然后退出应用程序的正确方法是什么? 我已经研究了几个相关问题,特别是这一个: 。。。但是,让我感到高兴的是,由于运行时错误而关闭应用程序 例如,下面的代码将创建4个任务,然后运行一个主循环。任务将在一段时间后抛出一个异常(AssertionError),以模拟“这永远不会发生”事件,我需要触发应用程序有序关闭 目前,此代码将在其任务内触发异常,并且该任务将中止。如果没有自定义异常处理程序,其他任务将继续,但至少应用程序将中止,但会在“RuntimeError:事件循环在将来完成之前停止”的情况下中止 我正在用Python 3.7进行测试Python异步IO任务中未处理异常后的整理,python,python-3.x,python-asyncio,Python,Python 3.x,Python Asyncio,在包含多个任务的python aysncio应用程序中,报告其中一个任务中未处理的异常然后退出应用程序的正确方法是什么? 我已经研究了几个相关问题,特别是这一个: 。。。但是,让我感到高兴的是,由于运行时错误而关闭应用程序 例如,下面的代码将创建4个任务,然后运行一个主循环。任务将在一段时间后抛出一个异常(AssertionError),以模拟“这永远不会发生”事件,我需要触发应用程序有序关闭 目前,此代码将在其任务内触发异常,并且该任务将中止。如果没有自定义异常处理程序,其他任务将继续,但至
#!/usr/bin/python3
import asyncio
class Test:
def __init__(self, loop):
loop.create_task( self.test(3))
loop.create_task( self.test(4))
loop.create_task( self.test(5))
loop.create_task( self.test(7))
def __enter__(self):
return self
def __exit__(self, type, value, tb):
pass
async def test(self, max):
i = 0
while True:
i = i + 1
print("Loop %d of %d" %(i,max))
assert i < max
await asyncio.sleep(1)
async def main(self):
while True:
print("Main loop doing stuff")
await asyncio.sleep(0.5)
def custom_exception_handler(loop, context):
# first, handle with default handler
loop.default_exception_handler(context)
loop.stop()
loop = asyncio.get_event_loop()
loop.set_exception_handler(custom_exception_handler)
with Test(loop) as t:
loop.run_until_complete( t.main() )
#/usr/bin/python3
导入异步
课堂测试:
定义初始化(自循环):
循环创建_任务(自测试(3))
循环创建_任务(自测试(4))
循环创建_任务(自测试(5))
循环创建任务(自测试(7))
定义输入(自我):
回归自我
定义退出(自身、类型、值、tb):
通过
异步def测试(自身,最大):
i=0
尽管如此:
i=i+1
打印(“循环%d,共%d”%(i,最大))
断言i
不要停止事件处理程序中的循环,只需捕获test()中的异常并优雅地终止main()。您会看到断言错误的回溯,因为默认异常处理程序会这样做。由于run_until_complete函数,其他一切都将自动发生,并且不会出现运行时异常或警告
一般来说,您不希望任务A中的异常关闭其他任务,但您的应用程序逻辑可能需要这样的功能。在这种情况下,您需要显式地编写一个机制来实现这一点。通常有一种比loop.stop()更好的终止循环的方法,除非使用run_forever()启动循环
您还可以查看Task.cancel(),它在更复杂的情况下可能很有用。如果您决定使用该函数,则被取消的任务应处理asyncio.CancelleError以实现正常终止。请注意,这不是Exception的子类,而是RuntimeException的子类,这是我第一次遇到的一个小细节
正如我的代码所示,我在Win10上使用了Python3.8,但我认为这无关紧要
#! python3.8
import asyncio
class Test:
def __init__(self, loop):
self.running = True
loop.create_task(self.test(3))
loop.create_task(self.test(4))
loop.create_task(self.test(5))
loop.create_task(self.test(7))
def __enter__(self):
return self
def __exit__(self, *_x):
pass
async def test(self, mx):
try:
i = 0
while True:
i = i + 1
print("Loop %d of %d" %(i, mx))
assert i < mx
await asyncio.sleep(1)
except Exception:
self.running = False
raise
async def main(self):
while self.running:
print("Main loop doing stuff")
await asyncio.sleep(0.5)
loop = asyncio.get_event_loop()
with Test(loop) as t:
loop.run_until_complete(t.main())
#!蟒蛇3.8
导入异步
课堂测试:
定义初始化(自循环):
self.running=True
循环创建_任务(自测试(3))
循环创建_任务(自测试(4))
循环创建_任务(自测试(5))
循环创建任务(自测试(7))
定义输入(自我):
回归自我
定义uuu退出uuu(自我,*x):
通过
异步def测试(自我、mx):
尝试:
i=0
尽管如此:
i=i+1
打印(“循环%d,共%d”%(i,mx))
断言i
下面是使用Task.cancel()函数的第二个解决方案:
#! python3.8
import asyncio
class Test:
def __init__(self, loop):
self.main_task = loop.create_task(self.main())
loop.set_exception_handler(self.custom_exception_handler)
loop.create_task(self.test(3))
loop.create_task(self.test(4))
loop.create_task(self.test(5))
loop.create_task(self.test(7))
def __enter__(self):
return self
def __exit__(self, *_x):
pass
async def test(self, mx):
i = 0
while True:
i = i + 1
print("Loop %d of %d" %(i, mx))
assert i < mx
await asyncio.sleep(1)
async def main(self):
try:
while True:
print("Main loop doing stuff")
await asyncio.sleep(0.5)
except asyncio.CancelledError:
pass
def custom_exception_handler(self, loop, context):
# first, handle with default handler
loop.default_exception_handler(context)
self.main_task.cancel()
loop = asyncio.get_event_loop()
with Test(loop) as t:
loop.run_until_complete(t.main_task)
#!蟒蛇3.8
导入异步
课堂测试:
定义初始化(自循环):
self.main\u task=loop.create\u task(self.main())
loop.set\u异常处理程序(self.custom\u异常处理程序)
循环创建_任务(自测试(3))
循环创建_任务(自测试(4))
循环创建_任务(自测试(5))
循环创建任务(自测试(7))
定义输入(自我):
回归自我
定义uuu退出uuu(自我,*x):
通过
异步def测试(自我、mx):
i=0
尽管如此:
i=i+1
打印(“循环%d,共%d”%(i,mx))
断言i
太棒了,谢谢!我曾尝试使用“取消”方法,但我错误地认为我需要取消的是4个“测试”任务,而它们正是需要处理CacelledError异常的地方。请接受答案,以便其他人知道它是有效的。现在完成,抱歉