Python Idle与KeyboardInterrupts
在使用Idle的时候,按Ctrl+C来中断程序大约有90%的成功率,但我在想为什么有时候它不管用。在Idle里,如果我执行了
import time
time.sleep(10)
然后再按Ctrl+C来中断程序,它通常要等10秒钟才会停止。
但是在命令行界面里,执行同样的代码,按Ctrl+C就能立刻中断程序。
2 个回答
快速看一下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信号。