asyncio -从任务中重新引发异常



我使用asyncio做一些TCP通信。我有一个Receive()函数在一个无限循环中做read()。使用asyncio.create_task(Receive())作为后台任务运行。

现在,如果连接被对等端关闭,则会引发异常(或可能是任何其他异常),我在Receive()函数中捕获该异常。但是,我想重新引发该异常,以便外部代码可以决定要做什么(例如重新连接)。

由于异常是在任务中引发的,我不知道如何检索它。

我试着创造一个例子来说明我的意思:

import asyncio
async def divide(x):
try:
return 1/x
except Exception as e:
print("Divide inner exception: ", e)
raise   # Re-raise so main() can handle it
async def someFn():
asyncio.create_task(divide(0))  # Exception is never retrieved
# await divide(0) # This will raise two exceptions - the original in divide() and in main()
async def main():
try:
await someFn()
# Do other things while someFn() runs
except Exception as e:
print("main exception: ", e)
asyncio.run(main())

如何在main()中获得任务异常?

如何在main()中获得任务异常?

您可以利用引发异常的任务完成的事实,而不是让任务在后台运行,实际上等待它的完成。这要求创建任务的代码不保留create_task()返回的任务对象,而是将其返回给调用者或将其存储到一组共享任务中。(像trio这样的库甚至不允许盲目地生成后台任务,而是要求每个任务都伴随着一个托儿所,该托儿所定义谁处理异常)。

例如:

async def someFn():
# set up a background task, but also return it to the caller
t = asyncio.create_task(divide(0))
return t
async def other_things():
await asyncio.sleep(1)
async def main():
try:
task = await someFn()
# await both the background task and other things, immediately
# propagating an exception in either
await asyncio.gather(task, other_things())
except Exception as e:
print("main exception: ", e)

另一个选择是使用add_done_callback,这允许一些灵活性,不必事先知道在代码中处理任务的位置(如果使用asyncio.gather()选项则需要这样做)。

import asyncio
async def divide(x):
try:
return 1/x
except Exception as e:
print("Divide inner exception: ", e)
raise   # Re-raise so callback can handle it 
# (or don't handle exception here and allow callback to manage)
async def someFn():
task = asyncio.create_task(divide(0))
task.add_done_callback(task_cb)
def task_cb(task):
try:
task.result()
except asyncio.CancelledError:
pass  # Task cancellation should not be logged as an error.
except Exception as e:
print('Exception raised by task: ', e)
async def main():
try:
await someFn()
# Do other things while someFn() runs
except Exception as e:
# Handle the exception in some way
print("main exception: ", e)
asyncio.run(main())

最新更新