为什么asyncio的事件循环在Windows上抑制KeyboardInterrupt?

33

我有一个非常简单的测试程序,除了执行一个asyncio事件循环外什么都不做:

import asyncio
asyncio.get_event_loop().run_forever()

当我在Linux上运行这个程序并按下Ctrl+C时,程序会正确地终止并引发一个 KeyboardInterrupt 异常。在Windows上按下Ctrl+C没有任何反应(在Python 3.4.2下测试过)。即使在Windows上,使用time.sleep()的简单无限循环也可以正确地触发 KeyboardInterrupt

import time
while True:
    time.sleep(3600)

为什么asyncio的事件循环在Windows上会抑制KeyboardInterrupt信号?

3个回答

23

有一个适用于Windows的解决方法。运行另一个协程,在每秒唤醒循环并允许循环对键盘中断做出反应。

以下是来自asyncio文档的Echo服务器示例:

async def wakeup():
    while True:
        await asyncio.sleep(1)

loop = asyncio.get_event_loop()
coro = loop.create_server(EchoServerClientProtocol, '127.0.0.1', 8888)
server = loop.run_until_complete(coro)

# add wakeup HACK
loop.create_task(wakeup())

try:
    loop.run_forever()
except KeyboardInterrupt:
    pass

20

这是一个错误,确实存在。

请参阅Python Bug跟踪器上的问题以了解解决进展。


9
Windows 上的 Ctrl-C 在 Python 3.8 中可以正常工作。详见 https://docs.python.org/dev/whatsnew/3.8.html#asyncio - Messa

14
如果您只想退出程序而不需要捕获KeyboardInterrupt,那么signal 模块提供了一种更简单(且更高效)的解决方法:
# This restores the default Ctrl+C signal handler, which just kills the process
import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)

# Now the event loop is interruptable
import asyncio
asyncio.get_event_loop().run_forever()

这个解决方案是否清理了套接字连接? - JustWe
@Jiu 这只会导致进程退出。任何打开的套接字都将被操作系统关闭。请参阅 https://superuser.com/questions/375604 了解更多信息。 - Bart Robinson

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