Python 空闲和键盘中断
空闲状态下的键盘中断在 90% 的情况下对我有效,但我想知道为什么它们并不总是有效。在空闲状态下,如果我这样做
import time
time.sleep(10)
,然后使用 Ctrl+C 尝试键盘中断,它不会中断该进程,直到休眠 10 秒后。
相同的代码和通过 Ctrl+C 实现的键盘中断可立即在 shell 中运行。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
快速浏览一下 IDLE 源代码就会发现,KeyboardInterrupts 有一些特殊情况处理: http://svn.python.org/view/python/tags/r267/Lib/idlelib/PyShell.py?annotate=88851
最重要的是,代码实际上是在主 IDLE gui 进程通过 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:
这将要求解释器在再次调用 PyErr_CheckSignals() 之前执行任意数量的字节码指令 - 这在 time.sleep() 期间可能不会发生。我敢说这是模拟 SIGINT 而不是实际发出 SIGINT 信号的缺陷。
A quick glance at the IDLE source reveals that KeyboardInterrupts have some special case handling: http://svn.python.org/view/python/tags/r267/Lib/idlelib/PyShell.py?annotate=88851
On top of that, code is actually executed in a separate process which the main IDLE gui process communicates with via RPC. You're going to get different behavior under that model - it's best to just test with the canonical interpreter (via command line, interactive, etc.)
============
Digging deeper...
The socket on the RPC server is managed in a secondary thread which is supposed to propagate a KeyboardInterrupt using a call to thread.interrupt_main() ( http://svn.python.org/view/python/tags/r267/Lib/idlelib/run.py?annotate=88851 ). Behavior is not as expected there... This posting hints that for some reason, interrupt_main doesn't provide the level of granularity that you would expect: http://bytes.com/topic/python/answers/38386-thread-interrupt_main-doesnt-seem-work
Async API functions in cPython are a little goofy (from my experience) due to how the interpreter loop is handled, so it doesn't surprise me. interrupt_main() calls PyErr_SetInterrupt() to asynchronously notify the interpreter to handle a SIGINT in the main thread. From http://docs.python.org/c-api/exceptions.html#PyErr_SetInterrupt:
That would require the interpreter to go though whatever number of bytecode instructions before PyErr_CheckSignals() is called again - something that probably doesn't happen during a time.sleep(). I would venture to say that's a wart of simulating a SIGINT rather than actually signaling a SIGINT.
请参阅这篇文章:
我引用:
这是有道理的,因为线程休眠了 10 秒,因此在 10 秒过去之前不能抛出异常。但是,ctrl + c 始终在 shell 中工作,因为您试图停止进程,而不是抛出 python KeyboardInterrupt 异常。
另请参阅之前回答的问题。
我希望这有帮助!
See This article:
I quote:
It makes some sense, because the thread is asleep for 10 seconds and so exceptions cannot be thrown until the 10 seconds pass. However, ctrl + c always work in the shell because you are trying to stop a process, not throw a python KeyboardInterrupt exception.
Also, see this previously answered question.
I hope this helps!