使asyncio事件循环响应Windows(和Unix)上的KeyboardInterrupt

时间:2018-06-18 04:17:31

标签: python signals python-asyncio

当我的程序收到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分钟)。

通过为SIGINT / SIGTERM添加处理程序,我设法在Unix系统上获得了我想要的效果:

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 :(得分:0)

但是,您可能有很多阻塞或高 cpu 函数在没有空间用于 KeyboardInterrupt 的情况下运行。 Asyncio 确实在 Windows 和 KeyboardInterrupts 方面存在问题,因此事件循环有时会挂起,但使用 self.client.run_until_complete(self.client.start(token)) 应该可以减轻或消除这些问题,至少以我的经验来看。但是对 loop.run_forever() 的调用总是有很小的机会错过中断并使程序挂起。