Python Idle与KeyboardInterrupts

12 投票
2 回答
5648 浏览
提问于 2025-04-16 20:57

在使用Idle的时候,按Ctrl+C来中断程序大约有90%的成功率,但我在想为什么有时候它不管用。在Idle里,如果我执行了

import time
time.sleep(10)

然后再按Ctrl+C来中断程序,它通常要等10秒钟才会停止。

但是在命令行界面里,执行同样的代码,按Ctrl+C就能立刻中断程序。

2 个回答

1

请看这篇 文章

我引用一下:

如果你试图通过按 Control-C 来停止一个 CPython 程序,解释器会抛出一个 KeyboardInterrupt 异常。

这有点道理,因为线程在休眠10秒钟,所以在这10秒内是无法抛出异常的。不过,在命令行中按 ctrl + c 总是有效,因为你是在尝试停止一个进程,而不是抛出 Python 的 KeyboardInterrupt 异常。

另外,可以看看之前回答过的这个 问题

希望这对你有帮助!

8

快速看一下IDLE的源代码,我们可以发现KeyboardInterrupt(键盘中断)有一些特殊的处理方式:http://svn.python.org/view/python/tags/r267/Lib/idlelib/PyShell.py?annotate=88851

而且,代码实际上是在一个单独的进程中执行,主IDLE图形界面进程通过RPC(远程过程调用)与它进行通信。在这种模型下,你会遇到不同的行为——最好还是直接用标准的解释器来测试(通过命令行、交互式等方式)。

============

深入挖掘一下……

RPC服务器上的套接字是在一个辅助线程中管理的,这个线程应该通过调用thread.interrupt_main()来传播KeyboardInterrupt(键盘中断)信号(http://svn.python.org/view/python/tags/r267/Lib/idlelib/run.py?annotate=88851)。但是那里的行为并不是我们预期的……这篇帖子暗示,由于某种原因,interrupt_main并没有提供你所期望的细粒度控制:http://bytes.com/topic/python/answers/38386-thread-interrupt_main-doesnt-seem-work

在cPython中,异步API函数有点奇怪(根据我的经验),因为解释器循环的处理方式,所以这让我并不感到惊讶。interrupt_main()调用PyErr_SetInterrupt()来异步通知解释器在主线程中处理SIGINT信号。从http://docs.python.org/c-api/exceptions.html#PyErr_SetInterrupt

这个函数模拟了SIGINT信号到达的效果——下一次调用PyErr_CheckSignals()时,将会引发KeyboardInterrupt。

这就需要解释器执行任意数量的字节码指令,才能再次调用PyErr_CheckSignals()——这在time.sleep()期间可能不会发生。我敢说,这更像是模拟SIGINT的一个缺陷,而不是实际发出SIGINT信号。

撰写回答