我正在使用 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()
中获取任务异常?
答案 0 :(得分:2)
如何在 main()
中获取任务异常?
您可以利用引发异常的任务完成这一事实,而不是让任务在后台运行,而是实际等待其完成。这要求创建任务的代码不保留 create_task()
返回的任务对象,而是将其返回给调用者或将其存储到共享任务集。 (诸如 trio 之类的库甚至不允许盲目地生成后台任务,而是要求每个任务都伴随着一个 nursery 来定义谁来处理其异常。
例如:
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)
答案 1 :(得分:0)
另一种选择是使用 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())