当另一个协同例程出现异常时,asyncio.wait不会停止具有websocket调用的协同例程



我有两个协同例程。一个处理到websocket服务器的连接。另一个人做了一些武断的事情。发生异常时,我想终止程序。然而,处理与websocket服务器连接的协同例程仍在运行
请参阅此示例(不需要任何websocket服务器,只需运行此代码,它就会尝试重新连接到服务器(:

import asyncio
import websockets

async def task1():
""" A dummy co-routine
After five iterations. raise an exception"""

i = 1
while True:
print(f"In task 1 iteration {i}")
if i == 5:
raise Exception("Terminate task 1")
i += 1
await asyncio.sleep(1)

async def task2():
""" Connect to websocket server"""
i = 1
while True:
print(f"Attempt {i} to connect to server")
try:
await websockets.connect("ws://localhost:9090")
except Exception as e:
print(e)
else:
break
i += 1
await asyncio.sleep(1)
async def main():
tasks = [task1(), task2()]
finished, unfinished = await asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION)
for task in finished:
try:
await task
except Exception as e:
print("Exception detected:", repr(e))

if __name__ == "__main__":
print("Start")
asyncio.run(main())
print("End")

输出为:

Start
In task 1 iteration 1
Attempt 1 to connect to server
In task 1 iteration 2
In task 1 iteration 3
Multiple exceptions: [Errno 10061] Connect call failed ('127.0.0.1', 9090), [Errno 10061] Connect call failed ('::1', 9090, 0, 0)
In task 1 iteration 4
Attempt 2 to connect to server
In task 1 iteration 5
Exception detected: Exception('Terminate task 1')
Attempt 3 to connect to server
Multiple exceptions: [Errno 10061] Connect call failed ('127.0.0.1', 9090), [Errno 10061] Connect call failed ('::1', 9090, 0, 0)
Attempt 4 to connect to server
Multiple exceptions: [Errno 10061] Connect call failed ('127.0.0.1', 9090), [Errno 10061] Connect call failed ('::1', 9090, 0, 0)
Attempt 5 to connect to server

这里怎么了
我使用的是python 3.7.7。websockets版本是8.1。

更新

我安装了python 3.8.2,结果不一样。一旦出现异常,应用程序就会终止。这是输出:

Start
Attempt 1 to connect to server
In task 1 iteration 1
In task 1 iteration 2
In task 1 iteration 3
[WinError 1225] The remote computer refused the network connection
In task 1 iteration 4
Attempt 2 to connect to server
In task 1 iteration 5
Exception detected: Exception('Terminate task 1')
End

对此有什么解释吗?

  1. task2()中重新引发Cancelled错误。否则,任务不会被取消
    main()退出时,asyncio.run将尝试取消所有正在运行的任务,并等待它们完成。except Exception语句捕获引发的CancelledError,并导致asyncio.run中的永久等待

以下是问题的可选选项,尽管它们是良好的实践。

  1. 使用asyncio.create_task()asyncio.ensure_future()包装协程对象,将其视为类似未来的对象(任务将在事件循环中调度(
  2. 反复检查未完成的任务并取消它们
  3. 优选地,await对取消的任务查看任何其他错误
async def task2():
""" Connect to websocket server"""
i = 1
while True:
print(f"Attempt {i} to connect to server")
try:
await websockets.connect("ws://localhost:9090")
except asyncio.CancelledError:
raise
except Exception as e:
print(e)
i += 1
await asyncio.sleep(1)
async def main():
tasks = [
asyncio.create_task(task1()),
asyncio.create_task(task2()),
]
finished, unfinished = await asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION)
for task in finished:
try:
await task
except Exception as e:
print("Exception detected:", repr(e))
for task in unfinished:
task.cancel()
for task in unfinished:
try:
await task.result()
except asyncio.CancelledError:
pass
except Exception as e:
print("Exception detected:", repr(e))

最新更新