python выходит из бесконечного цикла while с исключением KeyboardInterrupt

Мой цикл while не завершается при нажатии Ctrl+C. Похоже, он игнорирует мое исключение 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

Опять же, я не уверен, в чем проблема, но мой терминал даже не печатает два предупреждения о печати, которые у меня есть в моем исключении. Может ли кто-нибудь помочь мне разобраться с этой проблемой?


person sadmicrowave    schedule 27.12.2011    source источник
comment
Ваш первый except KeyboardInterrupt перехватывает исключение. Он не будет виден второму except (KeyboardInterrupt, SystemExit), если вы не поднимете его повторно.   -  person eumiro    schedule 27.12.2011
comment
@eumiro - я закомментировал первый KeyboardInterrupt и заменил содержимое исключения на «pass», но у меня все еще возникает та же проблема. Ctrl+C игнорируется (ps aux также показывает, что процесс все еще запущен)   -  person sadmicrowave    schedule 27.12.2011
comment
@eumiro Я также пытался повторно вызвать исключение KeyboardInterrupt, добавив raise KeyboardInterrupt() в первый except KeyboardInterrupt:, однако я все еще сталкиваюсь с той же проблемой.   -  person sadmicrowave    schedule 27.12.2011


Ответы (1)


Замените оператор 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

Два оператора печати в блоках except должны выполняться со вторым словом «(опять же)».

person wberry    schedule 27.12.2011
comment
Хотя вы не спрашивали об этом, оператор pass в вашем коде создает то, что называется спин-блокировкой. Спин-блокировки бесполезно потребляют ЦП и могут повлиять на производительность всей системы. Есть способы их избежать. Изучите использование объектов Queue.Queue для связи между потоками и модулей select.select или multiprocessing для связи между процессами. - person wberry; 27.12.2011
comment
Итак, мне приходит в голову, что моя главная проблема (я думал, что это не связано) заключается в том, что я дважды разветвлял свой скрипт, чтобы «демонизировать» его. В этом случае KeyboardInterrupt больше не подключены к одному и тому же терминалу (однако мой скрипт по-прежнему будет печатать выходные данные на активном терминале). Есть ли способ по-прежнему использовать KeyboardInterrupt (или другой способ завершить мой скрипт вручную) в демонизированной программе? - person sadmicrowave; 27.12.2011
comment
в настоящее время я искал идентификатор процесса в выводе ps aux и выполнял sudo kill [pid]; однако это не очищает мой код изящно перед его уничтожением. Мне нужно закрыть соединения с базой данных и удалить часы inotify перед тем, как убить программу. - person sadmicrowave; 27.12.2011
comment
Если вы вызываете os.fork напрямую или если используемый вами API дает вам pid дочернего процесса, вы можете os.kill(childpid, signal.SIGTERM) явно в своем блоке except (KeyboardInterrupt). Это приведет к передаче элемента управления-C дочернему процессу. - person wberry; 27.12.2011
comment
Но если это настоящий процесс-демон, это означает, что родитель вышел, оставив его работать самостоятельно, и вам придется использовать файл pid, т. е. демон записывает свой собственный pid в файл в известном месте. Затем сценарий оболочки может kill -TERM `cat $PIDFILE` завершить процесс демона. - person wberry; 27.12.2011
comment
Я использовал этот учебник для демонизации моего скрипта: motomastyle.com/daemonizing-a-python-script< /а> - person sadmicrowave; 27.12.2011
comment
Если моя проблема заключается в том, что KeyboardInterrupt не срабатывает из-за того, что сценарий был разветвлен, то как вообще включить команду os.kill() или os.popen() внутри моего блока KeyboardInterrupt? KeyboardInterrupt не срабатывает, поэтому внутри блока исключений ничего не сработает... - person sadmicrowave; 27.12.2011
comment
Как оказалось, я искал sudo kill -INT [pid]. Это отправляет SIGINT в процесс, и python интерпретирует его как KeyboardInterrupt. Итак, теперь я могу использовать исключение KeyboardInterrupt для обработки событий завершения работы программы. Это то, что я был после. Вы определенно привели меня в правильном направлении, хотя и с некоторой помощью @wardi на irc.freenode.net/#python - person sadmicrowave; 27.12.2011