【问题标题】:Proper signal order to safely stop process正确的信号顺序以安全地停止进程
【发布时间】:2014-03-06 05:45:23
【问题描述】:

我有一个长期运行的 Python 进程,如果它挂起并停止报告进度,我希望能够终止它。但是我想以一种允许它安全清理的方式向它发出信号,以防它没有完全挂断并且仍然有一些东西在运行可以优雅地响应信号。在彻底杀死它之前发送信号的最佳顺序是什么?

我目前正在做类似的事情:

def safe_kill(pid):
    for sig in [SIGTERM, SIGABRT, SIGINT, SIGKILL]:
         os.kill(pid, sig)
         time.sleep(1)
         if not pid_exists(pid):
             return

有更好的顺序吗?我知道 SIGKILL 完全绕过了这个过程,但是 SIGTERM/SIGABRT/SIGINT 之间是否有任何显着差异,或者就 Python 而言它们都具有相同的效果?

【问题讨论】:

  • 如果您希望它在任何这些信号之后进行清理,您将需要该进程来注册一个信号处理程序。我认为 Python 不会将其中任何一个变成异常。它只是停止。
  • 我认为这里的答案取决于你试图优雅地杀死的 python 进程——它是否注册了任何信号处理程序?如果是这样,它们是否记录在案?如果它没有注册任何处理程序,那么我想你先发送什么并不重要;-)
  • @user2357112 -- SIGINT 变成 KeyboardInterrupt IIRC ...
  • 对,忘了 Ctrl-C 是 SIGINT。我以为是 SIGHUP 什么的。
  • 如果您的 Python 进程挂起,您不应该解决它挂起的根本原因吗? :) 我看到人们使用守护进程来重新启动此类进程,而实际上他们应该努力使其根本不会卡住。谁重新启动restarter?

标签: python signals


【解决方案1】:

我认为停止进程的正确方法是 SIGTERM,然后在短暂超时后执行 SIGKILL。

如果该进程以标准方式处理信号,我认为 SIGINT 和 SIGABRT 是不必要的。 SIGINT 通常以与 SIGTERM 相同的方式处理,而 SIGABRT 通常由进程本身在 abort() (wikipedia) 上使用。

任何比小脚本更复杂的东西通常会实现自定义 SIGTERM 处理以正常关闭(清理所有资源等)。

例如,看看 Upstart。它是一个 init 守护进程 - 它启动和停止 Ubuntu 和其他一些发行版中的大部分进程。停止进程的默认 Upstart 行为是发送 SIGTERM,等待 5 秒并发送 SIGKILL(来源 - upstart cookbook)。

您可能应该进行一些测试以确定您的流程的最佳超时时间。

【讨论】:

    【解决方案2】:

    您需要注册一个信号处理程序,就像在 C 中一样。

    import signal
    import sys
    
    def clean_termination(signal):
        # perform your cleanup
        sys.exit(1)
    
    # register the signal handler for the signals specified in the question
    signal.signal(signal.SIGTERM, clean_termination)
    signal.signal(signal.SIGABRT, clean_termination)
    

    请注意,Python 将SIGINT 信号映射到KeyboardInterrupt 异常,您可以使用常规except 语句捕获该异常。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-16
      • 2016-03-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多