Python asyncio 程序不会退出
Python asyncio program won't exit
我有一个包含两个异步任务的 asyncio/Python 程序:
- 崩溃的
- 永远持续下去。
我希望我的整个程序在第一次崩溃后退出。我做不到。
import asyncio
import time
def infinite_while():
while True:
time.sleep(1)
async def task_1():
await asyncio.sleep(1)
assert False
async def task_2():
loop = asyncio.get_event_loop()
await loop.run_in_executor(None, lambda: infinite_while())
loop = asyncio.get_event_loop()
asyncio.set_event_loop(loop)
tasks = asyncio.gather(task_2(), task_1())
try:
loop.run_until_complete(tasks)
except (Exception, KeyboardInterrupt) as e:
print('ERROR', str(e))
exit()
打印错误但不退出。手动关闭时,程序打印以下堆栈跟踪:
Error in atexit._run_exitfuncs:
Traceback (most recent call last):
File "/usr/lib/python3.5/concurrent/futures/thread.py", line 39, in _python_exit
t.join()
File "/usr/lib/python3.5/threading.py", line 1054, in join
self._wait_for_tstate_lock()
File "/usr/lib/python3.5/threading.py", line 1070, in _wait_for_tstate_lock
elif lock.acquire(block, timeout):
KeyboardInterrupt
当任务中出现异常时,它永远不会传播到通过事件循环启动任务的范围,即 loop.run_until_complete(tasks)
调用。想一想,就好像异常仅在您的任务上下文中抛出,那是您有机会处理它的顶级范围,否则它将在 "background".
这就是说,您永远不会从任务中捕获 Exception
:
try:
loop.run_until_complete(tasks)
except (Exception, KeyboardInterrupt) as e:
print('ERROR', str(e))
exit()
...这就是事件循环的工作原理。想象一下,如果您的服务有多个任务,其中一个任务失败,整个服务就会停止。
您可以做的是 stop 当您在 task1
中捕获异常时手动执行事件循环,例如
async def task_1():
await asyncio.sleep(1)
try:
assert False
except Exception:
# get the eventloop reference somehow
eventloop.stop()
然而,这非常脏而且有点 hacky,所以我宁愿建议使用 的解决方案,它更干净、更安全。
我有一个包含两个异步任务的 asyncio/Python 程序:
- 崩溃的
- 永远持续下去。
我希望我的整个程序在第一次崩溃后退出。我做不到。
import asyncio
import time
def infinite_while():
while True:
time.sleep(1)
async def task_1():
await asyncio.sleep(1)
assert False
async def task_2():
loop = asyncio.get_event_loop()
await loop.run_in_executor(None, lambda: infinite_while())
loop = asyncio.get_event_loop()
asyncio.set_event_loop(loop)
tasks = asyncio.gather(task_2(), task_1())
try:
loop.run_until_complete(tasks)
except (Exception, KeyboardInterrupt) as e:
print('ERROR', str(e))
exit()
打印错误但不退出。手动关闭时,程序打印以下堆栈跟踪:
Error in atexit._run_exitfuncs:
Traceback (most recent call last):
File "/usr/lib/python3.5/concurrent/futures/thread.py", line 39, in _python_exit
t.join()
File "/usr/lib/python3.5/threading.py", line 1054, in join
self._wait_for_tstate_lock()
File "/usr/lib/python3.5/threading.py", line 1070, in _wait_for_tstate_lock
elif lock.acquire(block, timeout):
KeyboardInterrupt
当任务中出现异常时,它永远不会传播到通过事件循环启动任务的范围,即 loop.run_until_complete(tasks)
调用。想一想,就好像异常仅在您的任务上下文中抛出,那是您有机会处理它的顶级范围,否则它将在 "background".
这就是说,您永远不会从任务中捕获 Exception
:
try:
loop.run_until_complete(tasks)
except (Exception, KeyboardInterrupt) as e:
print('ERROR', str(e))
exit()
...这就是事件循环的工作原理。想象一下,如果您的服务有多个任务,其中一个任务失败,整个服务就会停止。
您可以做的是 stop 当您在 task1
中捕获异常时手动执行事件循环,例如
async def task_1():
await asyncio.sleep(1)
try:
assert False
except Exception:
# get the eventloop reference somehow
eventloop.stop()
然而,这非常脏而且有点 hacky,所以我宁愿建议使用