Python中如何使用KeyboardInterrupt异常退出无限循环的while循环。

7

当按下Ctrl+C时,我的while循环不会退出。它似乎忽略了我的KeyboardInterrupt异常。循环部分如下:

while True:
  try:
    if subprocess_cnt <= max_subprocess:
      try:
        notifier.process_events()
        if notifier.check_events():
          notifier.read_events()
      except KeyboardInterrupt:
        notifier.stop()
        break
    else:
      pass
  except (KeyboardInterrupt, SystemExit):
    print '\nkeyboardinterrupt found!'
    print '\n...Program Stopped Manually!'
    raise

我不确定问题出在哪里,但是我的终端从来没有打印出我在异常中设置的两个打印警告。有人能帮我解决这个问题吗?


2
你的第一个 except KeyboardInterrupt 捕获了异常。如果你不重新抛出它,它将对第二个 except (KeyboardInterrupt, SystemExit) 不可见。 - eumiro
@eumiro - 我已经注释掉了第一个KeyboardInterrupt,并用'pass'替换了异常的内容,但我仍然遇到同样的问题。Ctrl+C被忽略了(ps aux也显示进程仍在运行)。 - sadmicrowave
@eumiro 我也尝试通过在第一个 except KeyboardInterrupt: 中添加 raise KeyboardInterrupt() 来重新引发 KeyboardInterrupt 异常,但我仍然遇到了相同的问题。 - sadmicrowave
1个回答

15

将您的break语句替换为raise语句,如下所示:

while True:
  try:
    if subprocess_cnt <= max_subprocess:
      try:
        notifier.process_events()
        if notifier.check_events():
          notifier.read_events()
      except KeyboardInterrupt:
        notifier.stop()
        print 'KeyboardInterrupt caught'
        raise  # the exception is re-raised to be caught by the outer try block
    else:
      pass
  except (KeyboardInterrupt, SystemExit):
    print '\nkeyboardinterrupt caught (again)'
    print '\n...Program Stopped Manually!'
    raise
< p >在 < code >except 块中的这两个打印语句应该按照第二个出现 '(again)' 执行。


1
虽然您没有询问,但是您代码中的 pass 语句创建了所谓的自旋锁。自旋锁会不必要地消耗 CPU 资源,并可能影响整个系统的性能。有方法可以避免它们。请尝试使用 Queue.Queue 对象在线程之间进行通信,使用 select.selectmultiprocessing 模块在进程之间进行通信。 - wberry
目前我一直在搜索ps aux输出中的进程ID,并执行sudo kill [pid];但是,在杀死程序之前,这并不能优雅地清理我的代码。我需要在终止程序之前关闭数据库连接并删除inotify监视器。 - sadmicrowave
如果您直接调用 os.fork,或者使用的 API 给出了子进程的 pid,则可以在 except (KeyboardInterrupt) 块中显式地调用 os.kill(childpid, signal.SIGTERM)。这将会“传递”控制-C 到子进程。 - wberry
我使用了这个教程来将我的脚本变成守护进程:http://motomastyle.com/daemonizing-a-python-script/ - sadmicrowave
如果我的问题是因为脚本被分叉而导致的 KeyboardInterrupt 无法触发,那么如何在我的 KeyboardInterrupt 块内包含 os.kill() 或 os.popen() 命令可以触发呢?由于 KeyboardInterrupt 没有触发,所以异常块内的任何代码都不会执行... - sadmicrowave
显示剩余4条评论

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