JK *_*iho 8 python signals sigint python-asyncio
我已经阅读了所有可以找到的有关如何优雅地处理带有asyncio事件循环并以Ctrl-C终止的脚本的文章,而且在我不打印一个或多个回溯的情况下,我无法使其中的任何一个都能正常工作这样做。答案几乎无处不在,我还无法在这个小脚本中实现其中的任何一个:
import asyncio
import datetime
import functools
import signal
async def display_date(loop):
end_time = loop.time() + 5.0
while True:
print(datetime.datetime.now())
if (loop.time() + 1.0) >= end_time:
break
await asyncio.sleep(1)
def stopper(signame, loop):
print("Got %s, stopping..." % signame)
loop.stop()
loop = asyncio.get_event_loop()
for signame in ('SIGINT', 'SIGTERM'):
loop.add_signal_handler(getattr(signal, signame), functools.partial(stopper, signame, loop))
loop.run_until_complete(display_date(loop))
loop.close()
Run Code Online (Sandbox Code Playgroud)
我想让脚本退出,而不在Ctrl-C(或通过发送的SIGTERM / SIGINT kill)之后打印任何回溯。这段代码RuntimeError: Event loop stopped before Future completed.以我根据先前的答案尝试过的许多其他形式打印,我得到了很多其他类型的异常类和错误消息,却不知道如何解决它们。上面的代码现在很小,但是我之前所做的一些尝试不过是什么,而且都不是正确的。
如果您能够修改脚本以使其优雅地终止,那么不胜感激地向您解释为什么这样做是正确的方法。
Man*_*d3r 16
使用信号处理程序:
import asyncio
from signal import SIGINT, SIGTERM
async def main_coro():
try:
await awaitable()
except asyncio.CancelledError:
do_cleanup()
if __name__ == "__main__":
loop = asyncio.get_event_loop()
main_task = asyncio.ensure_future(main_coro())
for signal in [SIGINT, SIGTERM]:
loop.add_signal_handler(signal, main_task.cancel)
try:
loop.run_until_complete(main_task)
finally:
loop.close()
Run Code Online (Sandbox Code Playgroud)
在事件循环运行时停止它永远是无效的。
在这里,您需要捕获Ctrl-C,以向Python表示您希望自己处理它,而不是显示默认的stacktrace。这可以通过经典的try / except来完成:
coro = display_date(loop)
try:
loop.run_until_complete(coro)
except KeyboardInterrupt:
print("Received exit, exiting")
Run Code Online (Sandbox Code Playgroud)
而且,就您的用例而言,就是这样!对于更真实的程序,您可能需要清理一些资源。另请参见Asyncio协程的正常关闭