如何让在Windows和Unix上运行的asyncio事件循环响应KeyboardInterrupt?

3
当我的程序接收到一个KeyboardInterrupt时,我想调用一段代码(self.client.logout()),以提示在我的循环中运行的任务优雅地退出。
这是我的基本循环:
loop = asyncio.get_event_loop()

loop.run_until_complete(self.client.start(token))

我最初试图简单地处理一个KeyboardInterrupt

loop = asyncio.get_event_loop()

try:
    loop.run_until_complete(self.client.start(token))
except KeyboardInterrupt:
    loop.run_until_complete(self.client.logout())
finally:
    loop.close()

但是在按下Ctrl+C和调用self.client.logout()之间有一个很大的延迟(变量,约1分钟)。

我成功地在Unix系统上添加了SIGINT/SIGTERM处理程序以获得所需的效果:

import signal

loop = asyncio.get_event_loop()

# enable the bot to respond to SIGINT/SIGTERM (Unix only)
try:
    loop.add_signal_handler(signal.SIGINT, lambda: asyncio.ensure_future(self.client.logout())
    loop.add_signal_handler(signal.SIGTERM, lambda: asyncio.ensure_future(self.client.logout())
except NotImplementedError:
    pass   # program is running in Windows - nothing we can do

try:
    loop.run_until_complete(self.client.start(token))
except KeyboardInterrupt:
    loop.run_until_complete(self.client.logout())
finally:
    loop.close()

当我按下Ctrl+C或停止运行程序的systemd守护进程时,注销函数会立即被调用。

在Windows上我该怎么做才能实现同样的功能?

1个回答

0

可能有很多阻塞或高CPU函数在运行,没有空间来处理KeyboardInterrupt。虽然Asyncio在Windows和KeyboardInterrupt方面存在问题,因此事件循环有时会挂起,但是像您所使用的self.client.run_until_complete(self.client.start(token))应该可以缓解或消除这些问题,至少在我的经验中是如此。但是对loop.run_forever()的调用始终有一小部分机会会错过中断并使程序挂起。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接